From b62aad1f41be148b0af05de3729aafb41c06ec8e Mon Sep 17 00:00:00 2001 From: Frederic Massart Date: Thu, 26 Jul 2012 16:47:56 +0800 Subject: [PATCH 1/1] Initial commit --- config.json | 55 + lib/__init__.py | 0 lib/__init__.pyc | Bin 0 -> 129 bytes lib/config.py | 32 + lib/config.pyc | Bin 0 -> 1186 bytes lib/db.py | 47 + lib/db.pyc | Bin 0 -> 1913 bytes lib/moodle.py | 47 + lib/moodle.pyc | Bin 0 -> 1644 bytes lib/pymysql/CHANGELOG | 37 + lib/pymysql/LICENSE | 19 + lib/pymysql/README.rst | 41 + lib/pymysql/__init__.py | 131 +++ lib/pymysql/__init__.pyc | Bin 0 -> 5482 bytes lib/pymysql/charset.py | 174 ++++ lib/pymysql/charset.pyc | Bin 0 -> 9181 bytes lib/pymysql/connections.py | 1069 ++++++++++++++++++++ lib/pymysql/connections.pyc | Bin 0 -> 39463 bytes lib/pymysql/constants/CLIENT.py | 20 + lib/pymysql/constants/CLIENT.pyc | Bin 0 -> 749 bytes lib/pymysql/constants/COMMAND.py | 23 + lib/pymysql/constants/COMMAND.pyc | Bin 0 -> 811 bytes lib/pymysql/constants/ER.py | 472 +++++++++ lib/pymysql/constants/ER.pyc | Bin 0 -> 17057 bytes lib/pymysql/constants/FIELD_TYPE.py | 32 + lib/pymysql/constants/FIELD_TYPE.pyc | Bin 0 -> 835 bytes lib/pymysql/constants/FLAG.py | 15 + lib/pymysql/constants/FLAG.pyc | Bin 0 -> 519 bytes lib/pymysql/constants/SERVER_STATUS.py | 12 + lib/pymysql/constants/SERVER_STATUS.pyc | Bin 0 -> 597 bytes lib/pymysql/constants/__init__.py | 0 lib/pymysql/constants/__init__.pyc | Bin 0 -> 143 bytes lib/pymysql/converters.py | 356 +++++++ lib/pymysql/converters.pyc | Bin 0 -> 12688 bytes lib/pymysql/cursors.py | 410 ++++++++ lib/pymysql/cursors.pyc | Bin 0 -> 14523 bytes lib/pymysql/err.py | 147 +++ lib/pymysql/err.pyc | Bin 0 -> 6342 bytes lib/pymysql/example.py | 24 + lib/pymysql/tests/__init__.py | 13 + lib/pymysql/tests/base.py | 20 + lib/pymysql/tests/test_DictCursor.py | 56 + lib/pymysql/tests/test_SSCursor.py | 100 ++ lib/pymysql/tests/test_basic.py | 213 ++++ lib/pymysql/tests/test_example.py | 32 + lib/pymysql/tests/test_issues.py | 278 +++++ lib/pymysql/tests/thirdparty/__init__.py | 5 + .../tests/thirdparty/test_MySQLdb/__init__.py | 7 + .../tests/thirdparty/test_MySQLdb/capabilities.py | 292 ++++++ .../tests/thirdparty/test_MySQLdb/dbapi20.py | 853 ++++++++++++++++ .../test_MySQLdb/test_MySQLdb_capabilities.py | 115 +++ .../test_MySQLdb/test_MySQLdb_dbapi20.py | 210 ++++ .../test_MySQLdb/test_MySQLdb_nonstandard.py | 90 ++ lib/pymysql/times.py | 16 + lib/pymysql/times.pyc | Bin 0 -> 920 bytes lib/pymysql/util.py | 19 + lib/pymysql/util.pyc | Bin 0 -> 834 bytes lib/tools.py | 5 + lib/tools.pyc | Bin 0 -> 270 bytes moodle-install.py | 141 +++ 60 files changed, 5628 insertions(+) create mode 100644 config.json create mode 100644 lib/__init__.py create mode 100644 lib/__init__.pyc create mode 100644 lib/config.py create mode 100644 lib/config.pyc create mode 100644 lib/db.py create mode 100644 lib/db.pyc create mode 100644 lib/moodle.py create mode 100644 lib/moodle.pyc create mode 100644 lib/pymysql/CHANGELOG create mode 100644 lib/pymysql/LICENSE create mode 100644 lib/pymysql/README.rst create mode 100644 lib/pymysql/__init__.py create mode 100644 lib/pymysql/__init__.pyc create mode 100644 lib/pymysql/charset.py create mode 100644 lib/pymysql/charset.pyc create mode 100644 lib/pymysql/connections.py create mode 100644 lib/pymysql/connections.pyc create mode 100644 lib/pymysql/constants/CLIENT.py create mode 100644 lib/pymysql/constants/CLIENT.pyc create mode 100644 lib/pymysql/constants/COMMAND.py create mode 100644 lib/pymysql/constants/COMMAND.pyc create mode 100644 lib/pymysql/constants/ER.py create mode 100644 lib/pymysql/constants/ER.pyc create mode 100644 lib/pymysql/constants/FIELD_TYPE.py create mode 100644 lib/pymysql/constants/FIELD_TYPE.pyc create mode 100644 lib/pymysql/constants/FLAG.py create mode 100644 lib/pymysql/constants/FLAG.pyc create mode 100644 lib/pymysql/constants/SERVER_STATUS.py create mode 100644 lib/pymysql/constants/SERVER_STATUS.pyc create mode 100644 lib/pymysql/constants/__init__.py create mode 100644 lib/pymysql/constants/__init__.pyc create mode 100644 lib/pymysql/converters.py create mode 100644 lib/pymysql/converters.pyc create mode 100644 lib/pymysql/cursors.py create mode 100644 lib/pymysql/cursors.pyc create mode 100644 lib/pymysql/err.py create mode 100644 lib/pymysql/err.pyc create mode 100644 lib/pymysql/example.py create mode 100644 lib/pymysql/tests/__init__.py create mode 100644 lib/pymysql/tests/base.py create mode 100644 lib/pymysql/tests/test_DictCursor.py create mode 100644 lib/pymysql/tests/test_SSCursor.py create mode 100644 lib/pymysql/tests/test_basic.py create mode 100644 lib/pymysql/tests/test_example.py create mode 100644 lib/pymysql/tests/test_issues.py create mode 100644 lib/pymysql/tests/thirdparty/__init__.py create mode 100644 lib/pymysql/tests/thirdparty/test_MySQLdb/__init__.py create mode 100644 lib/pymysql/tests/thirdparty/test_MySQLdb/capabilities.py create mode 100644 lib/pymysql/tests/thirdparty/test_MySQLdb/dbapi20.py create mode 100644 lib/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_capabilities.py create mode 100644 lib/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py create mode 100644 lib/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_nonstandard.py create mode 100644 lib/pymysql/times.py create mode 100644 lib/pymysql/times.pyc create mode 100644 lib/pymysql/util.py create mode 100644 lib/pymysql/util.pyc create mode 100644 lib/tools.py create mode 100644 lib/tools.pyc create mode 100644 moodle-install.py diff --git a/config.json b/config.json new file mode 100644 index 0000000..b2643ec --- /dev/null +++ b/config.json @@ -0,0 +1,55 @@ +// Configuration file +{ + "dirs": { + "www": "/var/www/", + "store": "/var/www/repositories", + "cache": "/home/fred/.moodle" + }, + + "remotes": { + // "stable": "/Users/fmc/code/php/moodle.git", + // "integration": "/Users/fmc/code/php/integration.git", + "stable": "git://github.com/moodle/moodle.git", + "integration": "git://github.com/moodle/integration.git", + "mine": "git@github.com/FMCorz/moodle.git" + }, + + "host": "fred.moodle.local", + "login": "admin", + "passwd": "test", + + "db": { + "mysqli": { + "host": "localhost", + "port": "3306", + "user": "root", + "passwd": "root" + }, + "pgsql": { + "host": "localhost", + "port": "3306", + "user": "root", + "passwd": "root" + } + }, + + "wording": { + "prefixStable": "s", + "prefixIntegration": "i", + "prefixMaster": "m", + "suffixSeparator": "", + + "integration": "Integration", + "master": "Master", + "stable": "Stable", + + "mysqli": "MySQL", + "pgsql": "PostgreSQL" + }, + + "dataDir": "moodledata", + "wwwDir": "moodle", + "defaultEngine": "mysqli", + "phpEnv": "/usr/bin/php", + "useCacheAsRemote": false +} \ No newline at end of file diff --git a/lib/__init__.py b/lib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lib/__init__.pyc b/lib/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9cbb30426152b2d8c1760ad12a0fc6dfc578b4e1 GIT binary patch literal 129 zcmZSn%*%D~oa$(M7{CJ(V5kHb(G3m(q+-Z% zlcHh3T}`-(Q3VcP`yFN}-JENxUy@UlYs$S_r$MesYa|H#+M|`C5|hBut1x83jC1AHbRAv^2mwkjQ#+$T|OIq&Ni`z#ED4o7*wK~);ZrInTSB5^Zu@+vFQ zAI8Y)GMO8<2S1LdSz+Q>GOC3srL;DfpJ<-A$+ngc=1@^3=>|7VTq2=KQCTCZ35Yet zG~(1vepVVQ-A=_80d`1?WgE__xe2GWNyAB%ns9OLW>p!^)AO*%z9A-aBf4oeD>E0z zEfm^&45ZuYsrJ=f)loh2Rafv literal 0 HcmV?d00001 diff --git a/lib/db.py b/lib/db.py new file mode 100644 index 0000000..d6e82c0 --- /dev/null +++ b/lib/db.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +class DB(): + + conn = None + cur = None + engine = None + + def __init__(self, engine, options): + + self.engine = engine + + if engine == 'mysqli': + import pymysql + self.conn = pymysql.connect( + host=options['host'], + port=int(options['port']), + user=options['user'], + passwd=options['passwd'], + db=None + ) + self.cur = self.conn.cursor() + else: + raise Exception('DB engine %s not supported' % engine) + + def createdb(self, db): + + if self.engine == 'mysqli': + self.cur.execute('CREATE DATABASE %s DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci' % db) + + def dropdb(self, db): + + if self.engine == 'mysqli': + self.cur.execute('DROP DATABASE %s' % db) + + def dbexists(self, db): + + if self.engine == 'mysqli': + self.cur.execute("SELECT COUNT('*') FROM information_schema.SCHEMATA WHERE SCHEMA_NAME LIKE '%s'" % db) + count = self.cur.fetchone() + return count[0] > 0 + + def selectdb(self, db): + + if self.engine == 'mysqli': + self.cur.execute('USE %s' % db) diff --git a/lib/db.pyc b/lib/db.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bcea4601ce784fa528941c82ecabae09c4f5d040 GIT binary patch literal 1913 zcmcIl-%k@k5T3jKfL2sgK+%_b5UIq_S09X_Tn{mpLarsozFgYdEgZCW^>!N}ffw=B zztF^g!aqR2*()H%2Sc#e`8s<$`_1gk>^Aq~cKO@)*`1IkpB#SIAnGAN;F}|1(HEjK zq7NO6ZE98WnA0|(zJ9UL!f+j;-T)*~$0AXn4weJ+1`A9Gs!nmj*_mQKelyLESSgXn z8>LKst5O74$RXt+w;(P=eFdCYbV3vu1pyw~lpZsgAR1V7nxm5(9bgE>;38;sHptWB znF)?(3bZJS#-<1j@$gOyOkH3H2L(DP^4|H)6veZo5$ZI%UjWHx@DLJGLPSl?(GHK* z$3YbR#7A?``-##<86|0^jFn7{>8PvJCt>m^dg?KZ>+6n;_o7%jOUj88?WpmH*GXYK zm{pm9o`U)4*myH~n8dLRHMU3;#hIsO5=-NoC(Yt;oGS3K5me1#dq<%h=_rY_s&dRq z4*EVjFwBXWRsJ+yR3I6sr_ieV$xv4NsT9>P5wbcu*853Z9g4&1AnH{`ZxwHNT@XZZ zq=TRgT`d5}F4;5Ij8(GA)-0rK&DisH$UViv0lE;i0^l;B@v(tt^|M+BrUhrzrU3Fz4tn zPc6Y`j}tbjc@t{OYj`f|yS>|NSC&_npF11=_LdXH{UjZBxzPg^?#p3!wdHPlTWAgE z{if%8PBsjhwJpzSynW|6%S&oG0wWn0mmOeIW!kzgb%=(SSuQX7Ko_tmOvbUkZbyio zJc^W7OCVBwfVd;(tefo$F4e9%75}LhIB?u0xRylk1?%U%-K_9kKDimYGUAk8);F)S> Ww0xNu!|Qr6+kBO6>@{aVLFgCz-Cq^} literal 0 HcmV?d00001 diff --git a/lib/moodle.py b/lib/moodle.py new file mode 100644 index 0000000..ebae84d --- /dev/null +++ b/lib/moodle.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import os +import re + +from tools import debug + +class Moodle(): + + _path = None + _config = None + _installed = False + _settings = {} + + def __init__(self, path): + + self._path = path + self._config = os.path.join(path, 'config.php') + + if os.path.isfile(self._config): + self.load() + self._installed = True + else: + self._installed = False + + def installed(self): + return self._installed + + def load(self): + + if not self.installed(): + return None + + # Extracts parameters from config.php, does not handle params over multiple lines + prog = re.compile('^\s*\$CFG->([a-z]+)\s*=\s*(?P[\'"])(.+)(?P=brackets)\s*;$', re.I) + try: + f = open(self._config, 'r') + for line in f: + match = prog.search(line) + if match == None: continue + self._settings[match.group(1)] = match.group(3) + setattr(self, match.group(1), match.group(3)) + f.close() + + except Exception as e: + debug('Error while reading config file') \ No newline at end of file diff --git a/lib/moodle.pyc b/lib/moodle.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d353dd9c0fc3f423f7270a99accf393de9209758 GIT binary patch literal 1644 zcmbtU;cgR05T4yTo7iz6t%Ru50#Sv^r6}iNm9 z*5;)-&&(coL2e7oASd!jc;+FQ4vo81z%X|#)%etcxLagIuGeYQS(^jF5gS}3*xs#RgZk{R7Nqo5vLlt zK6qxUNip55XLZD?+&QUJKlAKko#*mIXJKxO3QXgmi@ zipu%4EKM$~-WGg}Q8`N6O(_J<1@ z#U`vva88h;@JX@?*$u!*_tZD~vg)gW&Uj8|B%S5*xnJA|e$Wm(=3+&UImGAI)5F>G z8-EMMaT`fV8H^$(DdP=Ei<@*cgO) zihT2B!PV31DusSP2YqV(BX!&X)K++EV}Dp_nXEx zYk$rFzO}}rc~MQ*T3D_zAft=$iJ1x1Mz%77>Bb0xGrOo6wjAz}c-Y!hG0#U(?M&Ka zGXd?iv4=Gl2vBpzd*pEv0!r$ABR*Map|a2YSDC4OVXGJlNgD)GlA~_yR8mevEejOI zubD;ak&J6Gp9#H~SK%7SeFsK*pu*s?3e?wXMO{(@>Z{*Q=m|JT literal 0 HcmV?d00001 diff --git a/lib/pymysql/CHANGELOG b/lib/pymysql/CHANGELOG new file mode 100644 index 0000000..5c423c3 --- /dev/null +++ b/lib/pymysql/CHANGELOG @@ -0,0 +1,37 @@ +Changes +-------- +0.4 -Miscellaneous bug fixes + -Implementation of SSL support + -Implementation of kill() + -Cleaned up charset functionality + -Fixed BIT type handling + -Connections raise exceptions after they are close()'d + -Full Py3k and unicode support + +0.3 -Implemented most of the extended DBAPI 2.0 spec including callproc() + -Fixed error handling to include the message from the server and support + multiple protocol versions. + -Implemented ping() + -Implemented unicode support (probably needs better testing) + -Removed DeprecationWarnings + -Ran against the MySQLdb unit tests to check for bugs + -Added support for client_flag, charset, sql_mode, read_default_file, + use_unicode, cursorclass, init_command, and connect_timeout. + -Refactoring for some more compatibility with MySQLdb including a fake + pymysql.version_info attribute. + -Now runs with no warnings with the -3 command-line switch + -Added test cases for all outstanding tickets and closed most of them. + -Basic Jython support added. + -Fixed empty result sets bug. + -Integrated new unit tests and refactored the example into one. + -Fixed bug with decimal conversion. + -Fixed string encoding bug. Now unicode and binary data work! + -Added very basic docstrings. + +0.2 -Changed connection parameter name 'password' to 'passwd' + to make it more plugin replaceable for the other mysql clients. + -Changed pack()/unpack() calls so it runs on 64 bit OSes too. + -Added support for unix_socket. + -Added support for no password. + -Renamed decorders to decoders. + -Better handling of non-existing decoder. diff --git a/lib/pymysql/LICENSE b/lib/pymysql/LICENSE new file mode 100644 index 0000000..102e72e --- /dev/null +++ b/lib/pymysql/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2010 PyMySQL contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/lib/pymysql/README.rst b/lib/pymysql/README.rst new file mode 100644 index 0000000..6c6e4d3 --- /dev/null +++ b/lib/pymysql/README.rst @@ -0,0 +1,41 @@ +==================== +PyMySQL Installation +==================== + +.. contents:: +.. + This package contains a pure-Python MySQL client library. + Documentation on the MySQL client/server protocol can be found here: + http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol + If you would like to run the test suite, edit the config parameters in + pymysql/tests/base.py. The goal of pymysql is to be a drop-in + replacement for MySQLdb and work on CPython 2.3+, Jython, IronPython, PyPy + and Python 3. We test for compatibility by simply changing the import + statements in the Django MySQL backend and running its unit tests as well + as running it against the MySQLdb and myconnpy unit tests. + +Requirements +------------- + ++ Python 2.4 or higher + + * http://www.python.org/ + + * 2.6 is the primary test environment. + +* MySQL 4.1 or higher + + * protocol41 support, experimental 4.0 support + +Installation +------------ + +# easy_install pymysql +# ... or ... +# python setup.py install + +Python 3.0 Support +------------------ + +Simply run the build-py3k.sh script from the local directory. It will +build a working package in the ./py3k directory. diff --git a/lib/pymysql/__init__.py b/lib/pymysql/__init__.py new file mode 100644 index 0000000..c1e6d03 --- /dev/null +++ b/lib/pymysql/__init__.py @@ -0,0 +1,131 @@ +''' +PyMySQL: A pure-Python drop-in replacement for MySQLdb. + +Copyright (c) 2010 PyMySQL contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +''' + +VERSION = (0, 5, None) + +from constants import FIELD_TYPE +from converters import escape_dict, escape_sequence, escape_string +from err import Warning, Error, InterfaceError, DataError, \ + DatabaseError, OperationalError, IntegrityError, InternalError, \ + NotSupportedError, ProgrammingError, MySQLError +from times import Date, Time, Timestamp, \ + DateFromTicks, TimeFromTicks, TimestampFromTicks + +import sys + +try: + frozenset +except NameError: + from sets import ImmutableSet as frozenset + try: + from sets import BaseSet as set + except ImportError: + from sets import Set as set + +threadsafety = 1 +apilevel = "2.0" +paramstyle = "format" + +class DBAPISet(frozenset): + + + def __ne__(self, other): + if isinstance(other, set): + return super(DBAPISet, self).__ne__(self, other) + else: + return other not in self + + def __eq__(self, other): + if isinstance(other, frozenset): + return frozenset.__eq__(self, other) + else: + return other in self + + def __hash__(self): + return frozenset.__hash__(self) + + +STRING = DBAPISet([FIELD_TYPE.ENUM, FIELD_TYPE.STRING, + FIELD_TYPE.VAR_STRING]) +BINARY = DBAPISet([FIELD_TYPE.BLOB, FIELD_TYPE.LONG_BLOB, + FIELD_TYPE.MEDIUM_BLOB, FIELD_TYPE.TINY_BLOB]) +NUMBER = DBAPISet([FIELD_TYPE.DECIMAL, FIELD_TYPE.DOUBLE, FIELD_TYPE.FLOAT, + FIELD_TYPE.INT24, FIELD_TYPE.LONG, FIELD_TYPE.LONGLONG, + FIELD_TYPE.TINY, FIELD_TYPE.YEAR]) +DATE = DBAPISet([FIELD_TYPE.DATE, FIELD_TYPE.NEWDATE]) +TIME = DBAPISet([FIELD_TYPE.TIME]) +TIMESTAMP = DBAPISet([FIELD_TYPE.TIMESTAMP, FIELD_TYPE.DATETIME]) +DATETIME = TIMESTAMP +ROWID = DBAPISet() + +def Binary(x): + """Return x as a binary type.""" + return str(x) + +def Connect(*args, **kwargs): + """ + Connect to the database; see connections.Connection.__init__() for + more information. + """ + from connections import Connection + return Connection(*args, **kwargs) + +def get_client_info(): # for MySQLdb compatibility + return '%s.%s.%s' % VERSION + +connect = Connection = Connect + +# we include a doctored version_info here for MySQLdb compatibility +version_info = (1,2,2,"final",0) + +NULL = "NULL" + +__version__ = get_client_info() + +def thread_safe(): + return True # match MySQLdb.thread_safe() + +def install_as_MySQLdb(): + """ + After this function is called, any application that imports MySQLdb or + _mysql will unwittingly actually use + """ + sys.modules["MySQLdb"] = sys.modules["_mysql"] = sys.modules["pymysql"] + +__all__ = [ + 'BINARY', 'Binary', 'Connect', 'Connection', 'DATE', 'Date', + 'Time', 'Timestamp', 'DateFromTicks', 'TimeFromTicks', 'TimestampFromTicks', + 'DataError', 'DatabaseError', 'Error', 'FIELD_TYPE', 'IntegrityError', + 'InterfaceError', 'InternalError', 'MySQLError', 'NULL', 'NUMBER', + 'NotSupportedError', 'DBAPISet', 'OperationalError', 'ProgrammingError', + 'ROWID', 'STRING', 'TIME', 'TIMESTAMP', 'Warning', 'apilevel', 'connect', + 'connections', 'constants', 'converters', 'cursors', + 'escape_dict', 'escape_sequence', 'escape_string', 'get_client_info', + 'paramstyle', 'threadsafety', 'version_info', + + "install_as_MySQLdb", + + "NULL","__version__", + ] diff --git a/lib/pymysql/__init__.pyc b/lib/pymysql/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..866f68280c988c71f3a8f35592b2688b266b2d34 GIT binary patch literal 5482 zcmbtX>vP-25nqzBEYWr(KjOFJvz#4$!5f4d+pJNeKV2NITddwcu7y+!3;XR3eu_eys_vu6Xp-{Z~xQzkM* z4q%g&Rd2-HEbb*`;1+SA7zE9CbaxPMI ziJVImT_)!;MOVnVLeW)nu2OW3oNER35{1{vxlYq1@^4USKR%!Z{{wnarSw(_4{N?m z;Z2GZIUtx`5aX(Xx<$?!_PksxE%>)(&yD$>Q$p~e5McesxI{l181)eu81*MIFzRD6 zD=c+bBC|^WAo@GefwN9N{uk)^9f6++{FFu&`g@5SOpDc;;O`3D5V%RB1);e&r}<3q z_XU0~@C$)o3j9jo*8;zx(UR=_cE0z4;2+YcEO<-{xsPa663nAH=CM#dnNwo=n4BlP z3VWRI$ed-{obSn;lR=%#c^NdwuhW9FMNX59MUF)VVcRCZAv>Rvxg>NuWG>6VCUb?% zRWjGeTqkpb%m-v{l2K%Cky#^io6Lt~;A1!#-d!hihs-BrK4s3PM&>TN+-#89By*3< zXJqb^`JBubWWFTx6`8Ned_(42G7rc+B=d;OV=_<3zzi4w)f>WUi$)vd{F%%W_13rf z2n-g8s@>`CwD*_R165b!N$TJ2PV=KARwhlxcY|1^{y6joe&olw8YZa{Vsp4rt!^db zX&Q`K{(kDD~ppH#Id( zeP1O*H8}FpkzZ4JqP%#j#(tV%LvomVK^(**<$>#XS_Nf(1U6YR%wKt_4`QRdEK3G~ z2Y$*Vg9$6^YwvnhN4U zI5Dild^rrFU?zdLix;vgG@oR!fc31YC^5m1e|<4)JUI-5?5L(pz^vgLP-cuA_%ZK- z9h>lP=7(Vw90KSqwjOIIH0&Sv2J&Yv${6$ND2d*-B*?16Ng6{WoB|4yz-1!wxj)Dm z!;RxAt0ft-5=< z+v!;l-vryX-QL!aV(nV({syE1r>tj~sNPP!)nZZA`X02`te@KIbPu%sbf>R&I<2M! zWW$1H^+wAoM8T-7R^8sMsb+n*{*<-Tssk>%%4CIhYJbOK6w9mQf2(hI+HA&Fr`^|> z)?lUXzuvlU_pF+#YrDq|+18!iT9w_29pDZo*w?lSF6?S?(CdhRgdMgAqvyJ)rd4l& z7sAtiD}0D%fLcSr2?qbgvtGg|uL5k_R;%gu54zTRg>k0<{A}Qjeb?ad{-Y6pz+y#Lob`H zuL9FSZcF{}!ngU1(jcE6?-bVYoaiiewv)U!8FOa)rl4bf-84bDiy|mjAlY~+q%vJ! z#56}OW>tI{^n=LHSydk3#6)8;oY%M0B#T#g9mRJj zbP0+hgyRvAao4!Hm*Gy@97co9L1O&Pv0Rj!k$Hh(G|gUyo34wyDtFzD@l@Zy7Pcp2 zK~!2PT`B+G;Ja9Q%ix=A`SbGc?Oc4zPPR#3<;|QV!!-GYFOhs^l>c&Ol>UI}ZUX!< zTW*2FBfPI|SuGDZ-t)JKR_bnaDy-R%g${hK*I|u_b!6-+=#AQ_^(4~NXq`(c41EJKs_Fk*?T6NAaQJsx~ z-t#le_~K$pC-_Lha}3@^O}Vp=Qr|Of<_-N9U^r9pwJNNEsB#;FqOQP~R~BZ&GCi7& zD)h)KKvS;$*)IT+H1#2_{o+$$IEkf`=dX_e`ceMs;7<&1JVy6jd?@5cUao?OZ|-dV zjiY8+=}K`&^N&_`65|^n$3-4u{~(`$-ITk2B|;@PW|x7CXJ1Q2T^2U&B55nE>@*Xi zqBLd49)0KN^ZhUPUKqMw=FX(YEK3sLL~;J@c3mInkAc=T1}sma+pPC3%_*e0ZPDD( zXy&QUGq}Kj(^W4qV1H}8q`A0hzUDN?Rdd%Rg4%n#4NGfoJT%`^TCND$*V(t5LeuMW zw_N0wy=xUs4+gz{eYdM64OyBu#+Terekcx`opybP1uZ;WYnn@1a#rS3L4X&3yUJP8-!KJR>AG{gE5#-N zu4rnuoy_|#SAPYhklHK#Nb(7yKiJdqt$6hU|XH`Q&(ne$gb72_jZdp ztJJsK2Qt&&G9$LXX>HlN^_HYov$KbY5I!E~JgpD+EC!94~$4DK_KY+|)t z7li~(5r%)Tva&{xii+~&GRBz!SS&A=S4-DRt;$B_bh%PmDxE2#bESHxTmY0?*)e3XLtg^gxPAFGOr$Kibf6L`c`G1z9*bD#w literal 0 HcmV?d00001 diff --git a/lib/pymysql/charset.py b/lib/pymysql/charset.py new file mode 100644 index 0000000..10a91bd --- /dev/null +++ b/lib/pymysql/charset.py @@ -0,0 +1,174 @@ +MBLENGTH = { + 8:1, + 33:3, + 88:2, + 91:2 + } + +class Charset: + def __init__(self, id, name, collation, is_default): + self.id, self.name, self.collation = id, name, collation + self.is_default = is_default == 'Yes' + +class Charsets: + def __init__(self): + self._by_id = {} + + def add(self, c): + self._by_id[c.id] = c + + def by_id(self, id): + return self._by_id[id] + + def by_name(self, name): + for c in self._by_id.values(): + if c.name == name and c.is_default: + return c + +_charsets = Charsets() +""" +Generated with: + +mysql -N -s -e "select id, character_set_name, collation_name, is_default +from information_schema.collations order by id;" | python -c "import sys +for l in sys.stdin.readlines(): + id, name, collation, is_default = l.split(chr(9)) + print '_charsets.add(Charset(%s, \'%s\', \'%s\', \'%s\'))' \ + % (id, name, collation, is_default.strip()) +" + +""" +_charsets.add(Charset(1, 'big5', 'big5_chinese_ci', 'Yes')) +_charsets.add(Charset(2, 'latin2', 'latin2_czech_cs', '')) +_charsets.add(Charset(3, 'dec8', 'dec8_swedish_ci', 'Yes')) +_charsets.add(Charset(4, 'cp850', 'cp850_general_ci', 'Yes')) +_charsets.add(Charset(5, 'latin1', 'latin1_german1_ci', '')) +_charsets.add(Charset(6, 'hp8', 'hp8_english_ci', 'Yes')) +_charsets.add(Charset(7, 'koi8r', 'koi8r_general_ci', 'Yes')) +_charsets.add(Charset(8, 'latin1', 'latin1_swedish_ci', 'Yes')) +_charsets.add(Charset(9, 'latin2', 'latin2_general_ci', 'Yes')) +_charsets.add(Charset(10, 'swe7', 'swe7_swedish_ci', 'Yes')) +_charsets.add(Charset(11, 'ascii', 'ascii_general_ci', 'Yes')) +_charsets.add(Charset(12, 'ujis', 'ujis_japanese_ci', 'Yes')) +_charsets.add(Charset(13, 'sjis', 'sjis_japanese_ci', 'Yes')) +_charsets.add(Charset(14, 'cp1251', 'cp1251_bulgarian_ci', '')) +_charsets.add(Charset(15, 'latin1', 'latin1_danish_ci', '')) +_charsets.add(Charset(16, 'hebrew', 'hebrew_general_ci', 'Yes')) +_charsets.add(Charset(18, 'tis620', 'tis620_thai_ci', 'Yes')) +_charsets.add(Charset(19, 'euckr', 'euckr_korean_ci', 'Yes')) +_charsets.add(Charset(20, 'latin7', 'latin7_estonian_cs', '')) +_charsets.add(Charset(21, 'latin2', 'latin2_hungarian_ci', '')) +_charsets.add(Charset(22, 'koi8u', 'koi8u_general_ci', 'Yes')) +_charsets.add(Charset(23, 'cp1251', 'cp1251_ukrainian_ci', '')) +_charsets.add(Charset(24, 'gb2312', 'gb2312_chinese_ci', 'Yes')) +_charsets.add(Charset(25, 'greek', 'greek_general_ci', 'Yes')) +_charsets.add(Charset(26, 'cp1250', 'cp1250_general_ci', 'Yes')) +_charsets.add(Charset(27, 'latin2', 'latin2_croatian_ci', '')) +_charsets.add(Charset(28, 'gbk', 'gbk_chinese_ci', 'Yes')) +_charsets.add(Charset(29, 'cp1257', 'cp1257_lithuanian_ci', '')) +_charsets.add(Charset(30, 'latin5', 'latin5_turkish_ci', 'Yes')) +_charsets.add(Charset(31, 'latin1', 'latin1_german2_ci', '')) +_charsets.add(Charset(32, 'armscii8', 'armscii8_general_ci', 'Yes')) +_charsets.add(Charset(33, 'utf8', 'utf8_general_ci', 'Yes')) +_charsets.add(Charset(34, 'cp1250', 'cp1250_czech_cs', '')) +_charsets.add(Charset(35, 'ucs2', 'ucs2_general_ci', 'Yes')) +_charsets.add(Charset(36, 'cp866', 'cp866_general_ci', 'Yes')) +_charsets.add(Charset(37, 'keybcs2', 'keybcs2_general_ci', 'Yes')) +_charsets.add(Charset(38, 'macce', 'macce_general_ci', 'Yes')) +_charsets.add(Charset(39, 'macroman', 'macroman_general_ci', 'Yes')) +_charsets.add(Charset(40, 'cp852', 'cp852_general_ci', 'Yes')) +_charsets.add(Charset(41, 'latin7', 'latin7_general_ci', 'Yes')) +_charsets.add(Charset(42, 'latin7', 'latin7_general_cs', '')) +_charsets.add(Charset(43, 'macce', 'macce_bin', '')) +_charsets.add(Charset(44, 'cp1250', 'cp1250_croatian_ci', '')) +_charsets.add(Charset(47, 'latin1', 'latin1_bin', '')) +_charsets.add(Charset(48, 'latin1', 'latin1_general_ci', '')) +_charsets.add(Charset(49, 'latin1', 'latin1_general_cs', '')) +_charsets.add(Charset(50, 'cp1251', 'cp1251_bin', '')) +_charsets.add(Charset(51, 'cp1251', 'cp1251_general_ci', 'Yes')) +_charsets.add(Charset(52, 'cp1251', 'cp1251_general_cs', '')) +_charsets.add(Charset(53, 'macroman', 'macroman_bin', '')) +_charsets.add(Charset(57, 'cp1256', 'cp1256_general_ci', 'Yes')) +_charsets.add(Charset(58, 'cp1257', 'cp1257_bin', '')) +_charsets.add(Charset(59, 'cp1257', 'cp1257_general_ci', 'Yes')) +_charsets.add(Charset(63, 'binary', 'binary', 'Yes')) +_charsets.add(Charset(64, 'armscii8', 'armscii8_bin', '')) +_charsets.add(Charset(65, 'ascii', 'ascii_bin', '')) +_charsets.add(Charset(66, 'cp1250', 'cp1250_bin', '')) +_charsets.add(Charset(67, 'cp1256', 'cp1256_bin', '')) +_charsets.add(Charset(68, 'cp866', 'cp866_bin', '')) +_charsets.add(Charset(69, 'dec8', 'dec8_bin', '')) +_charsets.add(Charset(70, 'greek', 'greek_bin', '')) +_charsets.add(Charset(71, 'hebrew', 'hebrew_bin', '')) +_charsets.add(Charset(72, 'hp8', 'hp8_bin', '')) +_charsets.add(Charset(73, 'keybcs2', 'keybcs2_bin', '')) +_charsets.add(Charset(74, 'koi8r', 'koi8r_bin', '')) +_charsets.add(Charset(75, 'koi8u', 'koi8u_bin', '')) +_charsets.add(Charset(77, 'latin2', 'latin2_bin', '')) +_charsets.add(Charset(78, 'latin5', 'latin5_bin', '')) +_charsets.add(Charset(79, 'latin7', 'latin7_bin', '')) +_charsets.add(Charset(80, 'cp850', 'cp850_bin', '')) +_charsets.add(Charset(81, 'cp852', 'cp852_bin', '')) +_charsets.add(Charset(82, 'swe7', 'swe7_bin', '')) +_charsets.add(Charset(83, 'utf8', 'utf8_bin', '')) +_charsets.add(Charset(84, 'big5', 'big5_bin', '')) +_charsets.add(Charset(85, 'euckr', 'euckr_bin', '')) +_charsets.add(Charset(86, 'gb2312', 'gb2312_bin', '')) +_charsets.add(Charset(87, 'gbk', 'gbk_bin', '')) +_charsets.add(Charset(88, 'sjis', 'sjis_bin', '')) +_charsets.add(Charset(89, 'tis620', 'tis620_bin', '')) +_charsets.add(Charset(90, 'ucs2', 'ucs2_bin', '')) +_charsets.add(Charset(91, 'ujis', 'ujis_bin', '')) +_charsets.add(Charset(92, 'geostd8', 'geostd8_general_ci', 'Yes')) +_charsets.add(Charset(93, 'geostd8', 'geostd8_bin', '')) +_charsets.add(Charset(94, 'latin1', 'latin1_spanish_ci', '')) +_charsets.add(Charset(95, 'cp932', 'cp932_japanese_ci', 'Yes')) +_charsets.add(Charset(96, 'cp932', 'cp932_bin', '')) +_charsets.add(Charset(97, 'eucjpms', 'eucjpms_japanese_ci', 'Yes')) +_charsets.add(Charset(98, 'eucjpms', 'eucjpms_bin', '')) +_charsets.add(Charset(99, 'cp1250', 'cp1250_polish_ci', '')) +_charsets.add(Charset(128, 'ucs2', 'ucs2_unicode_ci', '')) +_charsets.add(Charset(129, 'ucs2', 'ucs2_icelandic_ci', '')) +_charsets.add(Charset(130, 'ucs2', 'ucs2_latvian_ci', '')) +_charsets.add(Charset(131, 'ucs2', 'ucs2_romanian_ci', '')) +_charsets.add(Charset(132, 'ucs2', 'ucs2_slovenian_ci', '')) +_charsets.add(Charset(133, 'ucs2', 'ucs2_polish_ci', '')) +_charsets.add(Charset(134, 'ucs2', 'ucs2_estonian_ci', '')) +_charsets.add(Charset(135, 'ucs2', 'ucs2_spanish_ci', '')) +_charsets.add(Charset(136, 'ucs2', 'ucs2_swedish_ci', '')) +_charsets.add(Charset(137, 'ucs2', 'ucs2_turkish_ci', '')) +_charsets.add(Charset(138, 'ucs2', 'ucs2_czech_ci', '')) +_charsets.add(Charset(139, 'ucs2', 'ucs2_danish_ci', '')) +_charsets.add(Charset(140, 'ucs2', 'ucs2_lithuanian_ci', '')) +_charsets.add(Charset(141, 'ucs2', 'ucs2_slovak_ci', '')) +_charsets.add(Charset(142, 'ucs2', 'ucs2_spanish2_ci', '')) +_charsets.add(Charset(143, 'ucs2', 'ucs2_roman_ci', '')) +_charsets.add(Charset(144, 'ucs2', 'ucs2_persian_ci', '')) +_charsets.add(Charset(145, 'ucs2', 'ucs2_esperanto_ci', '')) +_charsets.add(Charset(146, 'ucs2', 'ucs2_hungarian_ci', '')) +_charsets.add(Charset(192, 'utf8', 'utf8_unicode_ci', '')) +_charsets.add(Charset(193, 'utf8', 'utf8_icelandic_ci', '')) +_charsets.add(Charset(194, 'utf8', 'utf8_latvian_ci', '')) +_charsets.add(Charset(195, 'utf8', 'utf8_romanian_ci', '')) +_charsets.add(Charset(196, 'utf8', 'utf8_slovenian_ci', '')) +_charsets.add(Charset(197, 'utf8', 'utf8_polish_ci', '')) +_charsets.add(Charset(198, 'utf8', 'utf8_estonian_ci', '')) +_charsets.add(Charset(199, 'utf8', 'utf8_spanish_ci', '')) +_charsets.add(Charset(200, 'utf8', 'utf8_swedish_ci', '')) +_charsets.add(Charset(201, 'utf8', 'utf8_turkish_ci', '')) +_charsets.add(Charset(202, 'utf8', 'utf8_czech_ci', '')) +_charsets.add(Charset(203, 'utf8', 'utf8_danish_ci', '')) +_charsets.add(Charset(204, 'utf8', 'utf8_lithuanian_ci', '')) +_charsets.add(Charset(205, 'utf8', 'utf8_slovak_ci', '')) +_charsets.add(Charset(206, 'utf8', 'utf8_spanish2_ci', '')) +_charsets.add(Charset(207, 'utf8', 'utf8_roman_ci', '')) +_charsets.add(Charset(208, 'utf8', 'utf8_persian_ci', '')) +_charsets.add(Charset(209, 'utf8', 'utf8_esperanto_ci', '')) +_charsets.add(Charset(210, 'utf8', 'utf8_hungarian_ci', '')) + +def charset_by_name(name): + return _charsets.by_name(name) + +def charset_by_id(id): + return _charsets.by_id(id) + diff --git a/lib/pymysql/charset.pyc b/lib/pymysql/charset.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fccdc1dc92a113c5519926eeb9db27f8ecc282a1 GIT binary patch literal 9181 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 i<<@CPk3X8PIcu=|49krhIBwL?k<+dJ= 65 and byte2int(data) <= 122: #data.isalnum(): + return data + return '.' + + try: + print "packet length %d" % len(data) + print "method call[1]: %s" % sys._getframe(1).f_code.co_name + print "method call[2]: %s" % sys._getframe(2).f_code.co_name + print "method call[3]: %s" % sys._getframe(3).f_code.co_name + print "method call[4]: %s" % sys._getframe(4).f_code.co_name + print "method call[5]: %s" % sys._getframe(5).f_code.co_name + print "-" * 88 + except ValueError: pass + dump_data = [data[i:i+16] for i in xrange(len(data)) if i%16 == 0] + for d in dump_data: + print ' '.join(map(lambda x:"%02X" % byte2int(x), d)) + \ + ' ' * (16 - len(d)) + ' ' * 2 + \ + ' '.join(map(lambda x:"%s" % is_ascii(x), d)) + print "-" * 88 + print "" + +def _scramble(password, message): + if password == None or len(password) == 0: + return int2byte(0) + if DEBUG: print 'password=' + password + stage1 = sha_new(password).digest() + stage2 = sha_new(stage1).digest() + s = sha_new() + s.update(message) + s.update(stage2) + result = s.digest() + return _my_crypt(result, stage1) + +def _my_crypt(message1, message2): + length = len(message1) + result = struct.pack('B', length) + for i in xrange(length): + x = (struct.unpack('B', message1[i:i+1])[0] ^ \ + struct.unpack('B', message2[i:i+1])[0]) + result += struct.pack('B', x) + return result + +# old_passwords support ported from libmysql/password.c +SCRAMBLE_LENGTH_323 = 8 + +class RandStruct_323(object): + def __init__(self, seed1, seed2): + self.max_value = 0x3FFFFFFFL + self.seed1 = seed1 % self.max_value + self.seed2 = seed2 % self.max_value + + def my_rnd(self): + self.seed1 = (self.seed1 * 3L + self.seed2) % self.max_value + self.seed2 = (self.seed1 + self.seed2 + 33L) % self.max_value + return float(self.seed1) / float(self.max_value) + +def _scramble_323(password, message): + hash_pass = _hash_password_323(password) + hash_message = _hash_password_323(message[:SCRAMBLE_LENGTH_323]) + hash_pass_n = struct.unpack(">LL", hash_pass) + hash_message_n = struct.unpack(">LL", hash_message) + + rand_st = RandStruct_323(hash_pass_n[0] ^ hash_message_n[0], + hash_pass_n[1] ^ hash_message_n[1]) + outbuf = StringIO.StringIO() + for _ in xrange(min(SCRAMBLE_LENGTH_323, len(message))): + outbuf.write(int2byte(int(rand_st.my_rnd() * 31) + 64)) + extra = int2byte(int(rand_st.my_rnd() * 31)) + out = outbuf.getvalue() + outbuf = StringIO.StringIO() + for c in out: + outbuf.write(int2byte(byte2int(c) ^ byte2int(extra))) + return outbuf.getvalue() + +def _hash_password_323(password): + nr = 1345345333L + add = 7L + nr2 = 0x12345671L + + for c in [byte2int(x) for x in password if x not in (' ', '\t')]: + nr^= (((nr & 63)+add)*c)+ (nr << 8) & 0xFFFFFFFF + nr2= (nr2 + ((nr2 << 8) ^ nr)) & 0xFFFFFFFF + add= (add + c) & 0xFFFFFFFF + + r1 = nr & ((1L << 31) - 1L) # kill sign bits + r2 = nr2 & ((1L << 31) - 1L) + + # pack + return struct.pack(">LL", r1, r2) + +def pack_int24(n): + return struct.pack('BBB', n&0xFF, (n>>8)&0xFF, (n>>16)&0xFF) + +def unpack_uint16(n): + return struct.unpack(' len(self.__data): + raise Exception('Invalid advance amount (%s) for cursor. ' + 'Position=%s' % (length, new_position)) + self.__position = new_position + + def rewind(self, position=0): + """Set the position of the data buffer cursor to 'position'.""" + if position < 0 or position > len(self.__data): + raise Exception("Invalid position to rewind cursor to: %s." % position) + self.__position = position + + def peek(self, size): + """Look at the first 'size' bytes in packet without moving cursor.""" + result = self.__data[self.__position:(self.__position+size)] + if len(result) != size: + error = ('Result length not requested length:\n' + 'Expected=%s. Actual=%s. Position: %s. Data Length: %s' + % (size, len(result), self.__position, len(self.__data))) + if DEBUG: + print error + self.dump() + raise AssertionError(error) + return result + + def get_bytes(self, position, length=1): + """Get 'length' bytes starting at 'position'. + + Position is start of payload (first four packet header bytes are not + included) starting at index '0'. + + No error checking is done. If requesting outside end of buffer + an empty string (or string shorter than 'length') may be returned! + """ + return self.__data[position:(position+length)] + + def read_length_coded_binary(self): + """Read a 'Length Coded Binary' number from the data buffer. + + Length coded numbers can be anywhere from 1 to 9 bytes depending + on the value of the first byte. + """ + c = byte2int(self.read(1)) + if c == NULL_COLUMN: + return None + if c < UNSIGNED_CHAR_COLUMN: + return c + elif c == UNSIGNED_SHORT_COLUMN: + return unpack_uint16(self.read(UNSIGNED_SHORT_LENGTH)) + elif c == UNSIGNED_INT24_COLUMN: + return unpack_int24(self.read(UNSIGNED_INT24_LENGTH)) + elif c == UNSIGNED_INT64_COLUMN: + # TODO: what was 'longlong'? confirm it wasn't used? + return unpack_int64(self.read(UNSIGNED_INT64_LENGTH)) + + def read_length_coded_string(self): + """Read a 'Length Coded String' from the data buffer. + + A 'Length Coded String' consists first of a length coded + (unsigned, positive) integer represented in 1-9 bytes followed by + that many bytes of binary data. (For example "cat" would be "3cat".) + """ + length = self.read_length_coded_binary() + if length is None: + return None + return self.read(length) + + def is_ok_packet(self): + return byte2int(self.get_bytes(0)) == 0 + + def is_eof_packet(self): + return byte2int(self.get_bytes(0)) == 254 # 'fe' + + def is_resultset_packet(self): + field_count = byte2int(self.get_bytes(0)) + return field_count >= 1 and field_count <= 250 + + def is_error_packet(self): + return byte2int(self.get_bytes(0)) == 255 + + def check_error(self): + if self.is_error_packet(): + self.rewind() + self.advance(1) # field_count == error (we already know that) + errno = unpack_uint16(self.read(2)) + if DEBUG: print "errno = %d" % errno + raise_mysql_exception(self.__data) + + def dump(self): + dump_packet(self.__data) + + +class FieldDescriptorPacket(MysqlPacket): + """A MysqlPacket that represents a specific column's metadata in the result. + + Parsing is automatically done and the results are exported via public + attributes on the class such as: db, table_name, name, length, type_code. + """ + + def __init__(self, *args): + MysqlPacket.__init__(self, *args) + self.__parse_field_descriptor() + + def __parse_field_descriptor(self): + """Parse the 'Field Descriptor' (Metadata) packet. + + This is compatible with MySQL 4.1+ (not compatible with MySQL 4.0). + """ + self.catalog = self.read_length_coded_string() + self.db = self.read_length_coded_string() + self.table_name = self.read_length_coded_string() + self.org_table = self.read_length_coded_string() + self.name = self.read_length_coded_string().decode(self.connection.charset) + self.org_name = self.read_length_coded_string() + self.advance(1) # non-null filler + self.charsetnr = struct.unpack(' 2: + use_unicode = True + + if compress or named_pipe: + raise NotImplementedError, "compress and named_pipe arguments are not supported" + + if ssl and (ssl.has_key('capath') or ssl.has_key('cipher')): + raise NotImplementedError, 'ssl options capath and cipher are not supported' + + self.ssl = False + if ssl: + if not SSL_ENABLED: + raise NotImplementedError, "ssl module not found" + self.ssl = True + client_flag |= SSL + for k in ('key', 'cert', 'ca'): + v = None + if ssl.has_key(k): + v = ssl[k] + setattr(self, k, v) + + if read_default_group and not read_default_file: + if sys.platform.startswith("win"): + read_default_file = "c:\\my.ini" + else: + read_default_file = "/etc/my.cnf" + + if read_default_file: + if not read_default_group: + read_default_group = "client" + + cfg = ConfigParser.RawConfigParser() + cfg.read(os.path.expanduser(read_default_file)) + + def _config(key, default): + try: + return cfg.get(read_default_group,key) + except: + return default + + user = _config("user",user) + passwd = _config("password",passwd) + host = _config("host", host) + db = _config("db",db) + unix_socket = _config("socket",unix_socket) + port = int(_config("port", port)) + charset = _config("default-character-set", charset) + + self.host = host + self.port = port + self.user = user or DEFAULT_USER + self.password = passwd + self.db = db + self.unix_socket = unix_socket + if charset: + self.charset = charset + self.use_unicode = True + else: + self.charset = DEFAULT_CHARSET + self.use_unicode = False + + if use_unicode is not None: + self.use_unicode = use_unicode + + client_flag |= CAPABILITIES + client_flag |= MULTI_STATEMENTS + if self.db: + client_flag |= CONNECT_WITH_DB + self.client_flag = client_flag + + self.cursorclass = cursorclass + self.connect_timeout = connect_timeout + + self._connect() + + self._result = None + self._affected_rows = 0 + self.host_info = "Not connected" + + self.messages = [] + self.set_charset(charset) + self.encoders = encoders + self.decoders = conv + + self.autocommit(False) + + if sql_mode is not None: + c = self.cursor() + c.execute("SET sql_mode=%s", (sql_mode,)) + + self.commit() + + if init_command is not None: + c = self.cursor() + c.execute(init_command) + + self.commit() + + + def close(self): + ''' Send the quit message and close the socket ''' + if self.socket is None: + raise Error("Already closed") + send_data = struct.pack('= i + 1: + i += 1 + + self.server_capabilities = struct.unpack('= i+12-1: + rest_salt = data[i:i+12] + self.salt += rest_salt + + def get_server_info(self): + return self.server_version + + Warning = Warning + Error = Error + InterfaceError = InterfaceError + DatabaseError = DatabaseError + DataError = DataError + OperationalError = OperationalError + IntegrityError = IntegrityError + InternalError = InternalError + ProgrammingError = ProgrammingError + NotSupportedError = NotSupportedError + +# TODO: move OK and EOF packet parsing/logic into a proper subclass +# of MysqlPacket like has been done with FieldDescriptorPacket. +class MySQLResult(object): + + def __init__(self, connection): + from weakref import proxy + self.connection = proxy(connection) + self.affected_rows = None + self.insert_id = None + self.server_status = 0 + self.warning_count = 0 + self.message = None + self.field_count = 0 + self.description = None + self.rows = None + self.has_next = None + self.unbuffered_active = False + + def __del__(self): + if self.unbuffered_active: + self._finish_unbuffered_query() + + def read(self): + self.first_packet = self.connection.read_packet() + + # TODO: use classes for different packet types? + if self.first_packet.is_ok_packet(): + self._read_ok_packet() + else: + self._read_result_packet() + + def init_unbuffered_query(self): + self.unbuffered_active = True + self.first_packet = self.connection.read_packet() + + if self.first_packet.is_ok_packet(): + self._read_ok_packet() + self.unbuffered_active = False + else: + self.field_count = byte2int(self.first_packet.read(1)) + self._get_descriptions() + + # Apparently, MySQLdb picks this number because it's the maximum + # value of a 64bit unsigned integer. Since we're emulating MySQLdb, + # we set it to this instead of None, which would be preferred. + self.affected_rows = 18446744073709551615 + + def _read_ok_packet(self): + ok_packet = OKPacketWrapper(self.first_packet) + self.affected_rows = ok_packet.affected_rows + self.insert_id = ok_packet.insert_id + self.server_status = ok_packet.server_status + self.warning_count = ok_packet.warning_count + self.message = ok_packet.message + + def _check_packet_is_eof(self, packet): + if packet.is_eof_packet(): + eof_packet = EOFPacketWrapper(packet) + self.warning_count = eof_packet.warning_count + self.has_next = eof_packet.has_next + return True + return False + + def _read_result_packet(self): + self.field_count = byte2int(self.first_packet.read(1)) + self._get_descriptions() + self._read_rowdata_packet() + + def _read_rowdata_packet_unbuffered(self): + # Check if in an active query + if self.unbuffered_active == False: return + + # EOF + packet = self.connection.read_packet() + if self._check_packet_is_eof(packet): + self.unbuffered_active = False + self.rows = None + return + + row = [] + for field in self.fields: + data = packet.read_length_coded_string() + converted = None + if field.type_code in self.connection.decoders: + converter = self.connection.decoders[field.type_code] + if DEBUG: print "DEBUG: field=%s, converter=%s" % (field, converter) + if data != None: + converted = converter(self.connection, field, data) + row.append(converted) + + self.affected_rows = 1 + self.rows = tuple((row)) + if DEBUG: self.rows + + def _finish_unbuffered_query(self): + # After much reading on the MySQL protocol, it appears that there is, + # in fact, no way to stop MySQL from sending all the data after + # executing a query, so we just spin, and wait for an EOF packet. + while self.unbuffered_active: + packet = self.connection.read_packet() + if self._check_packet_is_eof(packet): + self.unbuffered_active = False + + # TODO: implement this as an iteratable so that it is more + # memory efficient and lower-latency to client... + def _read_rowdata_packet(self): + """Read a rowdata packet for each data row in the result set.""" + rows = [] + while True: + packet = self.connection.read_packet() + if self._check_packet_is_eof(packet): + break + + row = [] + for field in self.fields: + data = packet.read_length_coded_string() + converted = None + if field.type_code in self.connection.decoders: + converter = self.connection.decoders[field.type_code] + if DEBUG: print "DEBUG: field=%s, converter=%s" % (field, converter) + if data != None: + converted = converter(self.connection, field, data) + row.append(converted) + + rows.append(tuple(row)) + + self.affected_rows = len(rows) + self.rows = tuple(rows) + if DEBUG: self.rows + + def _get_descriptions(self): + """Read a column descriptor packet for each column in the result.""" + self.fields = [] + description = [] + for i in xrange(self.field_count): + field = self.connection.read_packet(FieldDescriptorPacket) + self.fields.append(field) + description.append(field.description()) + + eof_packet = self.connection.read_packet() + assert eof_packet.is_eof_packet(), 'Protocol error, expecting EOF' + self.description = tuple(description) diff --git a/lib/pymysql/connections.pyc b/lib/pymysql/connections.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a5c0d27fdcaa7aaa452552848fdcfcd5f0014902 GIT binary patch literal 39463 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 H{p$Y%%;7Wz literal 0 HcmV?d00001 diff --git a/lib/pymysql/constants/CLIENT.py b/lib/pymysql/constants/CLIENT.py new file mode 100644 index 0000000..9d11ea1 --- /dev/null +++ b/lib/pymysql/constants/CLIENT.py @@ -0,0 +1,20 @@ + +LONG_PASSWORD = 1 +FOUND_ROWS = 1 << 1 +LONG_FLAG = 1 << 2 +CONNECT_WITH_DB = 1 << 3 +NO_SCHEMA = 1 << 4 +COMPRESS = 1 << 5 +ODBC = 1 << 6 +LOCAL_FILES = 1 << 7 +IGNORE_SPACE = 1 << 8 +PROTOCOL_41 = 1 << 9 +INTERACTIVE = 1 << 10 +SSL = 1 << 11 +IGNORE_SIGPIPE = 1 << 12 +TRANSACTIONS = 1 << 13 +SECURE_CONNECTION = 1 << 15 +MULTI_STATEMENTS = 1 << 16 +MULTI_RESULTS = 1 << 17 +CAPABILITIES = LONG_PASSWORD|LONG_FLAG|TRANSACTIONS| \ + PROTOCOL_41|SECURE_CONNECTION diff --git a/lib/pymysql/constants/CLIENT.pyc b/lib/pymysql/constants/CLIENT.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e8fe6f252968072cd10a19a722c9d2372fed482d GIT binary patch literal 749 zcmaiy%a7AA5XQf@yWMSf`&!=b!l@@JB*Y1!O*;+tJB{9?!{}|K6UzD(kS-?2Uy|&wgz_rTZg*?+km?Zdjxk6 z_89IyY!mJQ>}uxD^jVb9^7!FJ%D!*=0b!1myVuzln}UdJTw z&}h-Pi`iub~I^?R-RB_eL zkhd=xdj_az0V-O6gat@gfP@8x4AK-J4WW+F1x0wS6zXW6#ep#^olHGjndxOT%@Vyb zp6ykFSs2VcdlEW|q)4-sO0Tl%q*6pWGvZ1v0?*!rUc`ws#Joe0lI3$+NsY^FkK zJfBj{Bb~_1#DS2NAWn3ug$}c~Z>qV9QkeuIRUf729vTz+?mvNQ9;;YZxzZ$v3`=!n zJh#h8v83d;UTN8LzZT0dRhdbHR4!zcn(Fw6Me<9V2WKLPgNX`Ns-ziF82+MsN7M1L z%zu>Q&ztply>t2a+l~LS+m1KxEB$V6%J0{-zAgQytuMzSR8;CUX}C4-H#_(9I{&~I NqkKhZ*8cO>{{Z%nhJ644 literal 0 HcmV?d00001 diff --git a/lib/pymysql/constants/COMMAND.py b/lib/pymysql/constants/COMMAND.py new file mode 100644 index 0000000..4a757da --- /dev/null +++ b/lib/pymysql/constants/COMMAND.py @@ -0,0 +1,23 @@ + +COM_SLEEP = 0x00 +COM_QUIT = 0x01 +COM_INIT_DB = 0x02 +COM_QUERY = 0x03 +COM_FIELD_LIST = 0x04 +COM_CREATE_DB = 0x05 +COM_DROP_DB = 0x06 +COM_REFRESH = 0x07 +COM_SHUTDOWN = 0x08 +COM_STATISTICS = 0x09 +COM_PROCESS_INFO = 0x0a +COM_CONNECT = 0x0b +COM_PROCESS_KILL = 0x0c +COM_DEBUG = 0x0d +COM_PING = 0x0e +COM_TIME = 0x0f +COM_DELAYED_INSERT = 0x10 +COM_CHANGE_USER = 0x11 +COM_BINLOG_DUMP = 0x12 +COM_TABLE_DUMP = 0x13 +COM_CONNECT_OUT = 0x14 +COM_REGISTER_SLAVE = 0x15 diff --git a/lib/pymysql/constants/COMMAND.pyc b/lib/pymysql/constants/COMMAND.pyc new file mode 100644 index 0000000000000000000000000000000000000000..55aa1df85b49f8d66d037f65889eabb34c21b95a GIT binary patch literal 811 zcma))NsrS&5QSeR`@Rou%eToA&sJBfv3d+au7`eLC}5D}9EaC4X&NB%G3P8Ev> zi3_&;*;TH7^{Vaaw|?i#_hG!p@1w%^7km|883Y(+1*QVJg1G`!VXB}SObt|rse>9Y z4Nw!N32MQ#Ky8>dr~}ghbz!=o9!w9^hv|a`FayvKW(XR=j6h?UF=zra0Zn11pc%{z zG>4gku8}Stv6&-ZIEugHm7pr93F?A|pebkx+JcUtE9eROf`MQt7zxILiC`+23FeG& zam}QGM6DB*ZmqbM73nt9Ui3OFRa5O~mh|1!$`n!)Cy}etl{%L7(|=g z%XV?;Sv#wMrQ!Q5&92CA{U%E4APzctG)#!(~<+J{8Nir~Pt&p~LdS zy?u8%FHiKIA5Zti$2-oS3;X75izPeUIidH2i{$G)J6-7W-Ql_XLB(T6qw>G!4@2>q A)Bpeg literal 0 HcmV?d00001 diff --git a/lib/pymysql/constants/ER.py b/lib/pymysql/constants/ER.py new file mode 100644 index 0000000..553983f --- /dev/null +++ b/lib/pymysql/constants/ER.py @@ -0,0 +1,472 @@ + +ERROR_FIRST = 1000 +HASHCHK = 1000 +NISAMCHK = 1001 +NO = 1002 +YES = 1003 +CANT_CREATE_FILE = 1004 +CANT_CREATE_TABLE = 1005 +CANT_CREATE_DB = 1006 +DB_CREATE_EXISTS = 1007 +DB_DROP_EXISTS = 1008 +DB_DROP_DELETE = 1009 +DB_DROP_RMDIR = 1010 +CANT_DELETE_FILE = 1011 +CANT_FIND_SYSTEM_REC = 1012 +CANT_GET_STAT = 1013 +CANT_GET_WD = 1014 +CANT_LOCK = 1015 +CANT_OPEN_FILE = 1016 +FILE_NOT_FOUND = 1017 +CANT_READ_DIR = 1018 +CANT_SET_WD = 1019 +CHECKREAD = 1020 +DISK_FULL = 1021 +DUP_KEY = 1022 +ERROR_ON_CLOSE = 1023 +ERROR_ON_READ = 1024 +ERROR_ON_RENAME = 1025 +ERROR_ON_WRITE = 1026 +FILE_USED = 1027 +FILSORT_ABORT = 1028 +FORM_NOT_FOUND = 1029 +GET_ERRNO = 1030 +ILLEGAL_HA = 1031 +KEY_NOT_FOUND = 1032 +NOT_FORM_FILE = 1033 +NOT_KEYFILE = 1034 +OLD_KEYFILE = 1035 +OPEN_AS_READONLY = 1036 +OUTOFMEMORY = 1037 +OUT_OF_SORTMEMORY = 1038 +UNEXPECTED_EOF = 1039 +CON_COUNT_ERROR = 1040 +OUT_OF_RESOURCES = 1041 +BAD_HOST_ERROR = 1042 +HANDSHAKE_ERROR = 1043 +DBACCESS_DENIED_ERROR = 1044 +ACCESS_DENIED_ERROR = 1045 +NO_DB_ERROR = 1046 +UNKNOWN_COM_ERROR = 1047 +BAD_NULL_ERROR = 1048 +BAD_DB_ERROR = 1049 +TABLE_EXISTS_ERROR = 1050 +BAD_TABLE_ERROR = 1051 +NON_UNIQ_ERROR = 1052 +SERVER_SHUTDOWN = 1053 +BAD_FIELD_ERROR = 1054 +WRONG_FIELD_WITH_GROUP = 1055 +WRONG_GROUP_FIELD = 1056 +WRONG_SUM_SELECT = 1057 +WRONG_VALUE_COUNT = 1058 +TOO_LONG_IDENT = 1059 +DUP_FIELDNAME = 1060 +DUP_KEYNAME = 1061 +DUP_ENTRY = 1062 +WRONG_FIELD_SPEC = 1063 +PARSE_ERROR = 1064 +EMPTY_QUERY = 1065 +NONUNIQ_TABLE = 1066 +INVALID_DEFAULT = 1067 +MULTIPLE_PRI_KEY = 1068 +TOO_MANY_KEYS = 1069 +TOO_MANY_KEY_PARTS = 1070 +TOO_LONG_KEY = 1071 +KEY_COLUMN_DOES_NOT_EXITS = 1072 +BLOB_USED_AS_KEY = 1073 +TOO_BIG_FIELDLENGTH = 1074 +WRONG_AUTO_KEY = 1075 +READY = 1076 +NORMAL_SHUTDOWN = 1077 +GOT_SIGNAL = 1078 +SHUTDOWN_COMPLETE = 1079 +FORCING_CLOSE = 1080 +IPSOCK_ERROR = 1081 +NO_SUCH_INDEX = 1082 +WRONG_FIELD_TERMINATORS = 1083 +BLOBS_AND_NO_TERMINATED = 1084 +TEXTFILE_NOT_READABLE = 1085 +FILE_EXISTS_ERROR = 1086 +LOAD_INFO = 1087 +ALTER_INFO = 1088 +WRONG_SUB_KEY = 1089 +CANT_REMOVE_ALL_FIELDS = 1090 +CANT_DROP_FIELD_OR_KEY = 1091 +INSERT_INFO = 1092 +UPDATE_TABLE_USED = 1093 +NO_SUCH_THREAD = 1094 +KILL_DENIED_ERROR = 1095 +NO_TABLES_USED = 1096 +TOO_BIG_SET = 1097 +NO_UNIQUE_LOGFILE = 1098 +TABLE_NOT_LOCKED_FOR_WRITE = 1099 +TABLE_NOT_LOCKED = 1100 +BLOB_CANT_HAVE_DEFAULT = 1101 +WRONG_DB_NAME = 1102 +WRONG_TABLE_NAME = 1103 +TOO_BIG_SELECT = 1104 +UNKNOWN_ERROR = 1105 +UNKNOWN_PROCEDURE = 1106 +WRONG_PARAMCOUNT_TO_PROCEDURE = 1107 +WRONG_PARAMETERS_TO_PROCEDURE = 1108 +UNKNOWN_TABLE = 1109 +FIELD_SPECIFIED_TWICE = 1110 +INVALID_GROUP_FUNC_USE = 1111 +UNSUPPORTED_EXTENSION = 1112 +TABLE_MUST_HAVE_COLUMNS = 1113 +RECORD_FILE_FULL = 1114 +UNKNOWN_CHARACTER_SET = 1115 +TOO_MANY_TABLES = 1116 +TOO_MANY_FIELDS = 1117 +TOO_BIG_ROWSIZE = 1118 +STACK_OVERRUN = 1119 +WRONG_OUTER_JOIN = 1120 +NULL_COLUMN_IN_INDEX = 1121 +CANT_FIND_UDF = 1122 +CANT_INITIALIZE_UDF = 1123 +UDF_NO_PATHS = 1124 +UDF_EXISTS = 1125 +CANT_OPEN_LIBRARY = 1126 +CANT_FIND_DL_ENTRY = 1127 +FUNCTION_NOT_DEFINED = 1128 +HOST_IS_BLOCKED = 1129 +HOST_NOT_PRIVILEGED = 1130 +PASSWORD_ANONYMOUS_USER = 1131 +PASSWORD_NOT_ALLOWED = 1132 +PASSWORD_NO_MATCH = 1133 +UPDATE_INFO = 1134 +CANT_CREATE_THREAD = 1135 +WRONG_VALUE_COUNT_ON_ROW = 1136 +CANT_REOPEN_TABLE = 1137 +INVALID_USE_OF_NULL = 1138 +REGEXP_ERROR = 1139 +MIX_OF_GROUP_FUNC_AND_FIELDS = 1140 +NONEXISTING_GRANT = 1141 +TABLEACCESS_DENIED_ERROR = 1142 +COLUMNACCESS_DENIED_ERROR = 1143 +ILLEGAL_GRANT_FOR_TABLE = 1144 +GRANT_WRONG_HOST_OR_USER = 1145 +NO_SUCH_TABLE = 1146 +NONEXISTING_TABLE_GRANT = 1147 +NOT_ALLOWED_COMMAND = 1148 +SYNTAX_ERROR = 1149 +DELAYED_CANT_CHANGE_LOCK = 1150 +TOO_MANY_DELAYED_THREADS = 1151 +ABORTING_CONNECTION = 1152 +NET_PACKET_TOO_LARGE = 1153 +NET_READ_ERROR_FROM_PIPE = 1154 +NET_FCNTL_ERROR = 1155 +NET_PACKETS_OUT_OF_ORDER = 1156 +NET_UNCOMPRESS_ERROR = 1157 +NET_READ_ERROR = 1158 +NET_READ_INTERRUPTED = 1159 +NET_ERROR_ON_WRITE = 1160 +NET_WRITE_INTERRUPTED = 1161 +TOO_LONG_STRING = 1162 +TABLE_CANT_HANDLE_BLOB = 1163 +TABLE_CANT_HANDLE_AUTO_INCREMENT = 1164 +DELAYED_INSERT_TABLE_LOCKED = 1165 +WRONG_COLUMN_NAME = 1166 +WRONG_KEY_COLUMN = 1167 +WRONG_MRG_TABLE = 1168 +DUP_UNIQUE = 1169 +BLOB_KEY_WITHOUT_LENGTH = 1170 +PRIMARY_CANT_HAVE_NULL = 1171 +TOO_MANY_ROWS = 1172 +REQUIRES_PRIMARY_KEY = 1173 +NO_RAID_COMPILED = 1174 +UPDATE_WITHOUT_KEY_IN_SAFE_MODE = 1175 +KEY_DOES_NOT_EXITS = 1176 +CHECK_NO_SUCH_TABLE = 1177 +CHECK_NOT_IMPLEMENTED = 1178 +CANT_DO_THIS_DURING_AN_TRANSACTION = 1179 +ERROR_DURING_COMMIT = 1180 +ERROR_DURING_ROLLBACK = 1181 +ERROR_DURING_FLUSH_LOGS = 1182 +ERROR_DURING_CHECKPOINT = 1183 +NEW_ABORTING_CONNECTION = 1184 +DUMP_NOT_IMPLEMENTED = 1185 +FLUSH_MASTER_BINLOG_CLOSED = 1186 +INDEX_REBUILD = 1187 +MASTER = 1188 +MASTER_NET_READ = 1189 +MASTER_NET_WRITE = 1190 +FT_MATCHING_KEY_NOT_FOUND = 1191 +LOCK_OR_ACTIVE_TRANSACTION = 1192 +UNKNOWN_SYSTEM_VARIABLE = 1193 +CRASHED_ON_USAGE = 1194 +CRASHED_ON_REPAIR = 1195 +WARNING_NOT_COMPLETE_ROLLBACK = 1196 +TRANS_CACHE_FULL = 1197 +SLAVE_MUST_STOP = 1198 +SLAVE_NOT_RUNNING = 1199 +BAD_SLAVE = 1200 +MASTER_INFO = 1201 +SLAVE_THREAD = 1202 +TOO_MANY_USER_CONNECTIONS = 1203 +SET_CONSTANTS_ONLY = 1204 +LOCK_WAIT_TIMEOUT = 1205 +LOCK_TABLE_FULL = 1206 +READ_ONLY_TRANSACTION = 1207 +DROP_DB_WITH_READ_LOCK = 1208 +CREATE_DB_WITH_READ_LOCK = 1209 +WRONG_ARGUMENTS = 1210 +NO_PERMISSION_TO_CREATE_USER = 1211 +UNION_TABLES_IN_DIFFERENT_DIR = 1212 +LOCK_DEADLOCK = 1213 +TABLE_CANT_HANDLE_FT = 1214 +CANNOT_ADD_FOREIGN = 1215 +NO_REFERENCED_ROW = 1216 +ROW_IS_REFERENCED = 1217 +CONNECT_TO_MASTER = 1218 +QUERY_ON_MASTER = 1219 +ERROR_WHEN_EXECUTING_COMMAND = 1220 +WRONG_USAGE = 1221 +WRONG_NUMBER_OF_COLUMNS_IN_SELECT = 1222 +CANT_UPDATE_WITH_READLOCK = 1223 +MIXING_NOT_ALLOWED = 1224 +DUP_ARGUMENT = 1225 +USER_LIMIT_REACHED = 1226 +SPECIFIC_ACCESS_DENIED_ERROR = 1227 +LOCAL_VARIABLE = 1228 +GLOBAL_VARIABLE = 1229 +NO_DEFAULT = 1230 +WRONG_VALUE_FOR_VAR = 1231 +WRONG_TYPE_FOR_VAR = 1232 +VAR_CANT_BE_READ = 1233 +CANT_USE_OPTION_HERE = 1234 +NOT_SUPPORTED_YET = 1235 +MASTER_FATAL_ERROR_READING_BINLOG = 1236 +SLAVE_IGNORED_TABLE = 1237 +INCORRECT_GLOBAL_LOCAL_VAR = 1238 +WRONG_FK_DEF = 1239 +KEY_REF_DO_NOT_MATCH_TABLE_REF = 1240 +OPERAND_COLUMNS = 1241 +SUBQUERY_NO_1_ROW = 1242 +UNKNOWN_STMT_HANDLER = 1243 +CORRUPT_HELP_DB = 1244 +CYCLIC_REFERENCE = 1245 +AUTO_CONVERT = 1246 +ILLEGAL_REFERENCE = 1247 +DERIVED_MUST_HAVE_ALIAS = 1248 +SELECT_REDUCED = 1249 +TABLENAME_NOT_ALLOWED_HERE = 1250 +NOT_SUPPORTED_AUTH_MODE = 1251 +SPATIAL_CANT_HAVE_NULL = 1252 +COLLATION_CHARSET_MISMATCH = 1253 +SLAVE_WAS_RUNNING = 1254 +SLAVE_WAS_NOT_RUNNING = 1255 +TOO_BIG_FOR_UNCOMPRESS = 1256 +ZLIB_Z_MEM_ERROR = 1257 +ZLIB_Z_BUF_ERROR = 1258 +ZLIB_Z_DATA_ERROR = 1259 +CUT_VALUE_GROUP_CONCAT = 1260 +WARN_TOO_FEW_RECORDS = 1261 +WARN_TOO_MANY_RECORDS = 1262 +WARN_NULL_TO_NOTNULL = 1263 +WARN_DATA_OUT_OF_RANGE = 1264 +WARN_DATA_TRUNCATED = 1265 +WARN_USING_OTHER_HANDLER = 1266 +CANT_AGGREGATE_2COLLATIONS = 1267 +DROP_USER = 1268 +REVOKE_GRANTS = 1269 +CANT_AGGREGATE_3COLLATIONS = 1270 +CANT_AGGREGATE_NCOLLATIONS = 1271 +VARIABLE_IS_NOT_STRUCT = 1272 +UNKNOWN_COLLATION = 1273 +SLAVE_IGNORED_SSL_PARAMS = 1274 +SERVER_IS_IN_SECURE_AUTH_MODE = 1275 +WARN_FIELD_RESOLVED = 1276 +BAD_SLAVE_UNTIL_COND = 1277 +MISSING_SKIP_SLAVE = 1278 +UNTIL_COND_IGNORED = 1279 +WRONG_NAME_FOR_INDEX = 1280 +WRONG_NAME_FOR_CATALOG = 1281 +WARN_QC_RESIZE = 1282 +BAD_FT_COLUMN = 1283 +UNKNOWN_KEY_CACHE = 1284 +WARN_HOSTNAME_WONT_WORK = 1285 +UNKNOWN_STORAGE_ENGINE = 1286 +WARN_DEPRECATED_SYNTAX = 1287 +NON_UPDATABLE_TABLE = 1288 +FEATURE_DISABLED = 1289 +OPTION_PREVENTS_STATEMENT = 1290 +DUPLICATED_VALUE_IN_TYPE = 1291 +TRUNCATED_WRONG_VALUE = 1292 +TOO_MUCH_AUTO_TIMESTAMP_COLS = 1293 +INVALID_ON_UPDATE = 1294 +UNSUPPORTED_PS = 1295 +GET_ERRMSG = 1296 +GET_TEMPORARY_ERRMSG = 1297 +UNKNOWN_TIME_ZONE = 1298 +WARN_INVALID_TIMESTAMP = 1299 +INVALID_CHARACTER_STRING = 1300 +WARN_ALLOWED_PACKET_OVERFLOWED = 1301 +CONFLICTING_DECLARATIONS = 1302 +SP_NO_RECURSIVE_CREATE = 1303 +SP_ALREADY_EXISTS = 1304 +SP_DOES_NOT_EXIST = 1305 +SP_DROP_FAILED = 1306 +SP_STORE_FAILED = 1307 +SP_LILABEL_MISMATCH = 1308 +SP_LABEL_REDEFINE = 1309 +SP_LABEL_MISMATCH = 1310 +SP_UNINIT_VAR = 1311 +SP_BADSELECT = 1312 +SP_BADRETURN = 1313 +SP_BADSTATEMENT = 1314 +UPDATE_LOG_DEPRECATED_IGNORED = 1315 +UPDATE_LOG_DEPRECATED_TRANSLATED = 1316 +QUERY_INTERRUPTED = 1317 +SP_WRONG_NO_OF_ARGS = 1318 +SP_COND_MISMATCH = 1319 +SP_NORETURN = 1320 +SP_NORETURNEND = 1321 +SP_BAD_CURSOR_QUERY = 1322 +SP_BAD_CURSOR_SELECT = 1323 +SP_CURSOR_MISMATCH = 1324 +SP_CURSOR_ALREADY_OPEN = 1325 +SP_CURSOR_NOT_OPEN = 1326 +SP_UNDECLARED_VAR = 1327 +SP_WRONG_NO_OF_FETCH_ARGS = 1328 +SP_FETCH_NO_DATA = 1329 +SP_DUP_PARAM = 1330 +SP_DUP_VAR = 1331 +SP_DUP_COND = 1332 +SP_DUP_CURS = 1333 +SP_CANT_ALTER = 1334 +SP_SUBSELECT_NYI = 1335 +STMT_NOT_ALLOWED_IN_SF_OR_TRG = 1336 +SP_VARCOND_AFTER_CURSHNDLR = 1337 +SP_CURSOR_AFTER_HANDLER = 1338 +SP_CASE_NOT_FOUND = 1339 +FPARSER_TOO_BIG_FILE = 1340 +FPARSER_BAD_HEADER = 1341 +FPARSER_EOF_IN_COMMENT = 1342 +FPARSER_ERROR_IN_PARAMETER = 1343 +FPARSER_EOF_IN_UNKNOWN_PARAMETER = 1344 +VIEW_NO_EXPLAIN = 1345 +FRM_UNKNOWN_TYPE = 1346 +WRONG_OBJECT = 1347 +NONUPDATEABLE_COLUMN = 1348 +VIEW_SELECT_DERIVED = 1349 +VIEW_SELECT_CLAUSE = 1350 +VIEW_SELECT_VARIABLE = 1351 +VIEW_SELECT_TMPTABLE = 1352 +VIEW_WRONG_LIST = 1353 +WARN_VIEW_MERGE = 1354 +WARN_VIEW_WITHOUT_KEY = 1355 +VIEW_INVALID = 1356 +SP_NO_DROP_SP = 1357 +SP_GOTO_IN_HNDLR = 1358 +TRG_ALREADY_EXISTS = 1359 +TRG_DOES_NOT_EXIST = 1360 +TRG_ON_VIEW_OR_TEMP_TABLE = 1361 +TRG_CANT_CHANGE_ROW = 1362 +TRG_NO_SUCH_ROW_IN_TRG = 1363 +NO_DEFAULT_FOR_FIELD = 1364 +DIVISION_BY_ZERO = 1365 +TRUNCATED_WRONG_VALUE_FOR_FIELD = 1366 +ILLEGAL_VALUE_FOR_TYPE = 1367 +VIEW_NONUPD_CHECK = 1368 +VIEW_CHECK_FAILED = 1369 +PROCACCESS_DENIED_ERROR = 1370 +RELAY_LOG_FAIL = 1371 +PASSWD_LENGTH = 1372 +UNKNOWN_TARGET_BINLOG = 1373 +IO_ERR_LOG_INDEX_READ = 1374 +BINLOG_PURGE_PROHIBITED = 1375 +FSEEK_FAIL = 1376 +BINLOG_PURGE_FATAL_ERR = 1377 +LOG_IN_USE = 1378 +LOG_PURGE_UNKNOWN_ERR = 1379 +RELAY_LOG_INIT = 1380 +NO_BINARY_LOGGING = 1381 +RESERVED_SYNTAX = 1382 +WSAS_FAILED = 1383 +DIFF_GROUPS_PROC = 1384 +NO_GROUP_FOR_PROC = 1385 +ORDER_WITH_PROC = 1386 +LOGGING_PROHIBIT_CHANGING_OF = 1387 +NO_FILE_MAPPING = 1388 +WRONG_MAGIC = 1389 +PS_MANY_PARAM = 1390 +KEY_PART_0 = 1391 +VIEW_CHECKSUM = 1392 +VIEW_MULTIUPDATE = 1393 +VIEW_NO_INSERT_FIELD_LIST = 1394 +VIEW_DELETE_MERGE_VIEW = 1395 +CANNOT_USER = 1396 +XAER_NOTA = 1397 +XAER_INVAL = 1398 +XAER_RMFAIL = 1399 +XAER_OUTSIDE = 1400 +XAER_RMERR = 1401 +XA_RBROLLBACK = 1402 +NONEXISTING_PROC_GRANT = 1403 +PROC_AUTO_GRANT_FAIL = 1404 +PROC_AUTO_REVOKE_FAIL = 1405 +DATA_TOO_LONG = 1406 +SP_BAD_SQLSTATE = 1407 +STARTUP = 1408 +LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR = 1409 +CANT_CREATE_USER_WITH_GRANT = 1410 +WRONG_VALUE_FOR_TYPE = 1411 +TABLE_DEF_CHANGED = 1412 +SP_DUP_HANDLER = 1413 +SP_NOT_VAR_ARG = 1414 +SP_NO_RETSET = 1415 +CANT_CREATE_GEOMETRY_OBJECT = 1416 +FAILED_ROUTINE_BREAK_BINLOG = 1417 +BINLOG_UNSAFE_ROUTINE = 1418 +BINLOG_CREATE_ROUTINE_NEED_SUPER = 1419 +EXEC_STMT_WITH_OPEN_CURSOR = 1420 +STMT_HAS_NO_OPEN_CURSOR = 1421 +COMMIT_NOT_ALLOWED_IN_SF_OR_TRG = 1422 +NO_DEFAULT_FOR_VIEW_FIELD = 1423 +SP_NO_RECURSION = 1424 +TOO_BIG_SCALE = 1425 +TOO_BIG_PRECISION = 1426 +M_BIGGER_THAN_D = 1427 +WRONG_LOCK_OF_SYSTEM_TABLE = 1428 +CONNECT_TO_FOREIGN_DATA_SOURCE = 1429 +QUERY_ON_FOREIGN_DATA_SOURCE = 1430 +FOREIGN_DATA_SOURCE_DOESNT_EXIST = 1431 +FOREIGN_DATA_STRING_INVALID_CANT_CREATE = 1432 +FOREIGN_DATA_STRING_INVALID = 1433 +CANT_CREATE_FEDERATED_TABLE = 1434 +TRG_IN_WRONG_SCHEMA = 1435 +STACK_OVERRUN_NEED_MORE = 1436 +TOO_LONG_BODY = 1437 +WARN_CANT_DROP_DEFAULT_KEYCACHE = 1438 +TOO_BIG_DISPLAYWIDTH = 1439 +XAER_DUPID = 1440 +DATETIME_FUNCTION_OVERFLOW = 1441 +CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG = 1442 +VIEW_PREVENT_UPDATE = 1443 +PS_NO_RECURSION = 1444 +SP_CANT_SET_AUTOCOMMIT = 1445 +MALFORMED_DEFINER = 1446 +VIEW_FRM_NO_USER = 1447 +VIEW_OTHER_USER = 1448 +NO_SUCH_USER = 1449 +FORBID_SCHEMA_CHANGE = 1450 +ROW_IS_REFERENCED_2 = 1451 +NO_REFERENCED_ROW_2 = 1452 +SP_BAD_VAR_SHADOW = 1453 +TRG_NO_DEFINER = 1454 +OLD_FILE_FORMAT = 1455 +SP_RECURSION_LIMIT = 1456 +SP_PROC_TABLE_CORRUPT = 1457 +SP_WRONG_NAME = 1458 +TABLE_NEEDS_UPGRADE = 1459 +SP_NO_AGGREGATE = 1460 +MAX_PREPARED_STMT_COUNT_REACHED = 1461 +VIEW_RECURSIVE = 1462 +NON_GROUPING_FIELD_USED = 1463 +TABLE_CANT_HANDLE_SPKEYS = 1464 +NO_TRIGGERS_ON_SYSTEM_SCHEMA = 1465 +USERNAME = 1466 +HOSTNAME = 1467 +WRONG_STRING_LENGTH = 1468 +ERROR_LAST = 1468 diff --git a/lib/pymysql/constants/ER.pyc b/lib/pymysql/constants/ER.pyc new file mode 100644 index 0000000000000000000000000000000000000000..321a57e28e675363c2661235154f680eff7dd687 GIT binary patch literal 17057 zcmeI21()1b(uS+T%#02@=)_@8Pq%tTnI=o!o|y_Li7VhFcEA&6W@ct)W@hFrGc#nf z3}3x1Ck9%Hze7JbR&`pq!UOs zCf%516VgpcCX!Ah*_3oslFdjrBiWpEbCNAcw;NNQGn<(p^Y)CEb-|H`3imb|>APBqPm8_8{GZWKYsPN%kV$ zi)0Gv6cQy>lD$dyCfSE{ACi4Z_a)hnbU%`*q*F=uC*7aq0MY|U4kSI0WE$x-lIf(= zNe&`Ch~!|>gGmk{J%r>?(nCpRkj@|(B^@O>jPx*)!$}V(IfC>Ek|RlvBsq%oD3YT| zk0v>W^ca$3NslEtj`TQ^<4KPvIf3*9k`qZ!Bsq!nB$AU!PbN8q^c0d)Nlzs?jr25< z(@9S!IfL{Jk~2xqBsq)pERwTH&n7vC^c<3NNzWxYkMul}^GVMqxq$Qnk_$;MB)N$6 zB9e+%SkUMxq|cxk}FBCB)N+8Dw3;7uO_*M^cs?DNv|cj zj`TW`>q)OCxq+evRHxr6i$k~>N7 zB)N<9E|R-R?9N+Ba)9vKPLHv^b?X#Nk1j|jPx^-&q+Tg z`5NihNWM<`b&_w8euLzjq~9d@7U{Q0zD@dVlJAgyhvd7Y-zE7T>Gw#!Px^h5ACUfl z55Pk4Sz@`eTxxkp6_^r=&k6`5EcYNPbTGbCO?>{(|I}q`xHj73r@?eogvo zlHZX2hUB-Tza{w{>F-E>Px^b3Kal=`95$3z9#P{)yyE(l1H=O!{Y%zmWcg zS`3E3q&uv&_Ld2g{tS zbF$3EIv2~_taG!>!#WSkysY!G%*Q$(%lxeKvn;^60Ly}`3$iT4x)964tP8U&!nz2{ zqO6OuEXKMR%i^qyvn;{71j~}FOR_A*x)jUOtV^>j!@3O1vaHLpEXTSW%kr$tv#h|n z0?Uf5E3&M_x)RIEtShsu!nz8}s;sNBjAI?gvKs4ZEUUAw&awvU8Z2wFuF0|%>sl;p zv#!mu4(mEB<5|bEtjoGC%X+Nqv8>O!KFbEI8?bE1x*^L(tQ)aRV4c9SG3&-Go3L)e zGLdy6%ciWGvTVk>8O!FZo3m`ex&_OYtXr~d#kv*C)~s8zY{R+@%eJiBvTVn?9n1Et z+q3Mzx&zCOtUI#o#JUqpiM7Pi$J)nIW-YT+SSu_MYs6Azt+Mp9_OlGI4zR?mG0V=Z zJF^V34zko(Ybq$BBdjAV!YVAgu^cGx-ZLqtoyM{Wu3~hKkNQ12e2N%avme+MvL4DZgLMYWDC;Q8VXTL-9L{<;%Mq+cupG&HB+F5(N3k5udNj*1tjDk% z%X%!!ajeI&9M5_@%L%L}u$;(xBFjmvC$XH&dNRu?tf#P?%6clxX{@KQoX&bW%NeX^ zu$;+yCd*l@XR(~kdN#{Btmm+t%X%)$d93HLoX>hb%LS|#uw2M`A6tk!a%K9nGXU@-AKjU=#=aw8#{rQ}R zUjV-Zeg*s*_zmz|;CI09fjE&4A5; zEr2b7t$?k8ZGdfo?SSop9e^Eyoq!V12b6&d5CK)79~b~)U}stU~6C- zU|V22V0&N(U`Jplpak>*WuO8?Ko#f*27nmY85jg=KpkiRO`ru#0umqv+CT@G3=9Fo zzzAT)BJ+R1uE1`<=6O90*JUrUM572Lp!y zhXONzQQ$D(aNr2wNZ=^oXy6#&Sl~F|c;E!!MBpUgWZ)FwRNyq=bl?o&OyDfwY~UQ= zT;M$5eBc7$Lf|6cV&D?sQs6S+a^MQ!O5iHsYTz2+THre1df*1&M&KskX5bd!R^T?^ zcHj=+PT(%!Zr~o^Uf@39e&7M%LEs_aVc-$qQQ$G)ao`EyN#H5qY2X>)Swmy|*DPHc zwJIV-NzzQRYMi9)(RuB9pp*`j2L?yyv%ed0TB_q>4qP-xE!ClsC>>qQ{wwzAnYRiawdjz$-@-ioJ^ zdL>TArV^eAQ(3AQv>G=mSvr!oqk5J^Wq;o%-XFEIv|Vbu2)ZppmC^Z&S8L7k;MnY& zt*88&*RvQAO-8ibpY!|i#^x9Zq_Q@YbcJ3 zvXt6>lq$_eZN!Du?6jNJdQ@*FBd$nxoi(c&rkl4y?wv+7+=|NWsFFp^>L>(JhM;U0 zeA3OJ5BbYUlr}p_+4L3f_Sx19G}GcaygN{8RMLUcV1xzRyGvVJrLR=BSJJE!HDZk8 zcb2p}vuh9Q%}gc3bFhIcj@5OY8=@Pg!wIFuMQ>6Mt|Nq6t@Sm{-oJy zxzxigzYY($d4<-rQ_oVf!g9Ok(aEJ+Ckpa+A-9{&tcLDm6JI-+tEsk6!SxgZ%az@) zp>epjr)}q<9=+2`ZL?iHTBRf{b_rcX^;UZ%o79QyrJ#ikmqze85L(=@xy2^ns9NgO z+TL~D{)k&~XB4uh#6#V0xM9I$nVep^v^emwqj3^tT6GZeh_SGXj6qJT$>PMtl<+W~63< z-HnA^_M4HVaet#!^W7-!LFsIPxu-PiF2}YR!I5AMaVs^qmMcRLT$Xmq1DW~BXn1s4 zd!$$X?I@|ojZ(Xrq<#-;N;9(>TWeO_H0J`tX-C6tcQ>$qOy1o;48mK3PtQljuGgBT zn{lHW{7k84-Gxg`t5CT<7YDS~y=h_&Vsey~%#2*6($VfM4;(?&Eu2B#(37}fR?!aq zx^1>9h*!ay+%E=W3PNZPxPQfigXZ{Vb^-Z={%YzQ>mw99YL4D_!UO|NG^?mJ``rhw zVBLiQAsK`f(+S&}EVyat%B;72S*}37?17Rkx=`dX@tE&$8yd5kyq_W7H<~L z>8tLll{CvyrISRXE8BBn15EiX{=0WI&HS%Vn7$=xHq#TmWBIIHN5cNVs$=`pyxLG) zj(o9&x#qs7(Mf+v~=V#{b zVHP@CtiC*83$rj{-qN-W?gFB6FW`NqGq>fsRy+p-PMSk$EFn5u9$_|RikT#xMvo7( zFk~a_+>9HeNJ!lK=l&vY!+h;uSYE5t9!Nbr zqan|hptb&<$Jbiimz2yo!k>-xU$OAxju!K&nvmNjO7~l)U2(%K8EfkAavDd zm}bun6MDNm;Fi=0 zw&^aRJMBEd%q?>{dpT%kPvFUH3AP>HvoAG?Tm(Vw;B^b-GL1q~fsJr+Cbo=Wi#;Ay zSF#7|@h~3fQ9}5-eETtTTcnE{UbR2540se%@{wkj9w17D9iQD@$gjw+yfgO-VcO_6 zw1xG${LN?B5|TXPZEV}BQn|G4W5EAIw0fY$C^omO$9ci>n!?^@7re)Ek5i>Lw zq?t*hACAm2VP9uqB*jx}IvxXczeshQ|w`r!>n`JkvarM=^{kw1q!Q`_g8DlTOQAi(3jtaBYB21@{cMfo8ulqaAypa0j06r0vAk?yfAz-UWyR)BF!S`RF+7 z=&QFpG z_QpI%Wpq_*%#FPm6caF?n3k$hR&Q1!-wia*l2}2P%Q#2D4SM3@;_*09v|G4G4g`7H zV5{Q|991ipu?(13vk(U@Ej6;X8E|T00Gf)9!_MdTVI^_fJD#aMY1V3XL>P48&2*<) z>!bsS`XN`E>7LK6Ws#um?=_;Ka0r`?y;M5&mb>KMRUn55{ntx&m`yB+Y}iO4vkQki z&*03U`Z{r~GCGgF5FT|!$loeVE@Z=@r>=5)PFrmUkBo^y{%{=Okc%lm3p4XV5SpbV zy#j;>D#B}i;GSGcV)staf^uSY1#>Jox1=R=0Uoc$8k4A1vV*hd9;Kv#@i8`(2KlUc z_+0LuFJb3QElsQ;xWg9H8qy@s2GVvj9B4utI~%t-Wn{ro0PaG!h18x z6ZYphtz~(BO7q9?zB|u6E`IeUBoWNs9Bl_ikd7j>A#Ff5pCWrgu9o-U0R>VwpMV?K zuoSjfiL2EpvG={80h{;9SIlGkEZ}s*N_t&gwOynf9&#$4=|*-?aiPE!MBb~Vn%$sn zE+jL<9J>>ABgh$3?NMYu@w3c$b9hOf5EFg7-~fE503h z4qP@<`f9ZSVao=xGhf$)u&w~?VOeP&>`vF^xyJ8jxov*qdGfN4R#dv@mRrs5-(IYXGa`BY17n_JilbOqrAC*{61 z7?tTkGqIfyP8%M@LSHknT)my;tLv`Y^OG>|>L3<5x{5sypJa*xZw>|X>@h#iS+m=i zC4c4~5N~iaPkriXr!Q!Z$!il=Jg9HiU$yHvK_FHq-Ua4lSwS`s)mm1fad%lBDc9mM z28UJHu?5@h;oGd=a{qArEAqLq$KV((Nily}3C_s_spa*hP?rid73;UsF{2pmo)!_= zeT}(#*<@@VLZa8Z4>pB?5HsO2Qac;ip<&jLjb2S2HM?oHgX0g}mU)Aae#2pf9U4Mm zE_ankea2dQohU|vSM*W_veIti<)RWhePohZ;V#d^plf+!U&l@?o^WH(ywMKjrMwkg zn+codqOue+aT9R4)OO_@ve@8xWYt1wIOC-rq`No#6j$8AF8dune3>h;Rd^1AVf=;< zooAD#HWrxNjxdbhYMV4{aN8NAp#DlHg>pCBwjo`uaRI|&l=}PaSb-wL#IC^8Q1L}+ z+ubdkX%bCtTH(=i{M2{d?QZP#O?zISP46c0d^I*(Sk&R9O;P}4TjPPK!c&lhi4Qju8VVkhW+J1YCFph1xxIb22TO9PHm zu0dX)#fcUHHFtP0gQ|Tnfi$iDk2@95x^hoz{Y*x{_Ae9RK;UPxPRl$GbTGFH+Y`8Q z*ZZ!1+6e`PSGOAvF`l-dw&zX?S%~E*mRp)If>SJx#pV%0m~$!imRnk(%8-8&sHgqD zH@LJ9Dpr!g;lPX;H($_yp_2vM?+A zc-;0}w3V3(=VkY?h9oi_3Kf2P2T$0ite`NS%7sb_4hWSoh~hr96$j$y31*jiM9Jo_2D1<&Zs`F`8iJ69Vwt;B879`0RVHM08D zOsfnnNW9FrLlwnT#PUA(pMJ)+KG1;dE0+Q;-4*s;+bX=4gZX*vKoQ&{sI^$ilBWiZ zkvKSIq$yZIVHEJqRh-A#Nxz2>d(Fo5Z75Z7OoX5YEU!u2%VC@#xp22gd2(TtOP2JZ z|8U?#?5x_FaOmjkKvH(-Wj^Ts9=&GvN;kpqWlb7(%d?kxm=+;nlFbnK;( z?(Ohq;Y!9Hg5gb$E$W-(t!h^*Sy|N`s(pJbo_4PYGYLD`?AsZitFRDr$3f@a9p~`? z>gQeNg3i-4Utn*$ITnlC-cN6H5putBqitWOFplSv{zjNj&AxPdo4Yo@QIAj#L#8#> z)>9O5_3{UES6S!_)DQVY+A8$Lz6doT*09|$6w``X-CWT;i=XpTu03s$zz2g$nS;;6 z7Q}?UTu1YoAPTP7aJ1W8ycFZ-I15dtj6vkZ(ZtUjo-6odD^@}FQ)u5vCQ;J#g3xT^ zSkH?XtVpiM&Nsf{P+y;R*kns@tw7`+%v=4kaMj44@g3v89lH|LKT*W-7hKw2t*#Vx zF>F;=-B8PH7snjjiA^_?#NRLKF?OoLpn1Wj)v;IbC1oJ)vyb!@cNf((itNV#7ED~G zGd)rawyZcaALEW z`FEOnsnx=~d=8$?)Jy$w_|--$wZoo$r5$s!$l&a%oo(#fG`83FrP}q(Tl|}Ep58#s zb44*J+Pclv`NwfLOlX+j&3{Sars?+J6Ef|GZ}bEn-!F$t<`=D{xXG6-xa zRR@n?iIg38AegZ6J}Y+t!R^h)TtilD2~p4mvx6elvN&0UrEbFD`4D1o5p7LjEUCb^ zyIE(^A2sWd{gfcfeLwC8O}5FSGGx_wo9|$+(dPDMi7(2}`C~4G{7zmfD>`UIkVnVL z3?A4}bFzHUVzbxj{M%Cqvmxk);sQ=(o_gdV*qvS|GDC}IAJd_*_F7)y38fo^z~D>s zRMdrm0a3@sW*5OawF*+G+!QT1sJQEO6{zF<-jC>R63;^EArDku=e3{TgkMgDV1}IB zQVV?BfezTQ40XM5N)A7?@nc7~LN~hy##tY;Y4^O_&Rm|1kFN8Thx|}rCTp664++SX z@@(Gsccz)l^z2vkqiR{W9TIESx)sDJqB zYuc|g@I}Mpw@)pUZNu+QP(%;MOjvHQ4|e#o1ZHF?uGsHCP{worU^!wOcEQXw@F>47&u3f5VlZDWvh?g0EK@RdSv zHZea-o4NOvjjcV;S>eOX8`+Oz?8jt7?nUyHq?oHmCHnzX_$2^-N)t-dw&471XjzXJ zXx)cev%AsYq4Gjtk#z+X@o#RfIG#*GG3={%%iNwh_c5dFmU3J@>h_t{w!#7yoCkbD z_+5oLBQFZW*||u&2UgcXlo344B3y=Gg&p_Pb3R4vT5y?`4Vt=j>-}a4FmHU6C@eYG zZv3_r+u(Wud-ipN+=b6^&uWM7x~OnX&hwGbZdaZOVix z2kG7u4nAshzk{Yvn5GBVpVN+-amazzK7GdMp3_HXOo)<=>^?@`ZrVY5*nxZRfM1x- XxYvGQIuHNvzyC?#e-ilrAc6k_RzLE@ literal 0 HcmV?d00001 diff --git a/lib/pymysql/constants/FIELD_TYPE.py b/lib/pymysql/constants/FIELD_TYPE.py new file mode 100644 index 0000000..3df7ff4 --- /dev/null +++ b/lib/pymysql/constants/FIELD_TYPE.py @@ -0,0 +1,32 @@ + + +DECIMAL = 0 +TINY = 1 +SHORT = 2 +LONG = 3 +FLOAT = 4 +DOUBLE = 5 +NULL = 6 +TIMESTAMP = 7 +LONGLONG = 8 +INT24 = 9 +DATE = 10 +TIME = 11 +DATETIME = 12 +YEAR = 13 +NEWDATE = 14 +VARCHAR = 15 +BIT = 16 +NEWDECIMAL = 246 +ENUM = 247 +SET = 248 +TINY_BLOB = 249 +MEDIUM_BLOB = 250 +LONG_BLOB = 251 +BLOB = 252 +VAR_STRING = 253 +STRING = 254 +GEOMETRY = 255 + +CHAR = TINY +INTERVAL = ENUM diff --git a/lib/pymysql/constants/FIELD_TYPE.pyc b/lib/pymysql/constants/FIELD_TYPE.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ca90e1f52fc5c21a20e055870f050de10e1edfcf GIT binary patch literal 835 zcmbV|NsrS&5QSg%eVKjbo)eJ}2ZRv9ne@z9vYjY#2Bj|1C>2D+Bmry=bK^Jh*AV;K z&xwFDw*0xPx~l8F&b+Uc-+pNHr`S9x`+s7;=$(ZEVwr-ZplL`Nnt^1XSx6R|gXExj zNFG{%6re>&5n6(jpk+uIT7gucRY(TiBH65;tTPW_(psueh@#2Ulu{@j%CbAU32F8ju%rz=mz7M zLWY;UL71exUT~45&b^)!#uV7?jXIu5c7u`U#Z(!(z8Qv&-;XJrO@A8QAiQ@!sqQ-A zx{cLIAu~z9>0{#z5=nu1nv_!Bl`}ZIw0T}s#|>lN2KWC_ZGw@X><>-25fh9j9k17k zd2PPwx+8xbQ!0h6BMwc>7U& zJ+xta6wO{o?PrT=d%DtD`{ix?e6?&Z^o3n6ZlhN>HouJG>t!6Z&t2nnC*inn?%FyY Y{b;e$H#f7#^c+2~$fy3}P3Kd;0k!awuK)l5 literal 0 HcmV?d00001 diff --git a/lib/pymysql/constants/FLAG.py b/lib/pymysql/constants/FLAG.py new file mode 100644 index 0000000..f9ebfad --- /dev/null +++ b/lib/pymysql/constants/FLAG.py @@ -0,0 +1,15 @@ +NOT_NULL = 1 +PRI_KEY = 2 +UNIQUE_KEY = 4 +MULTIPLE_KEY = 8 +BLOB = 16 +UNSIGNED = 32 +ZEROFILL = 64 +BINARY = 128 +ENUM = 256 +AUTO_INCREMENT = 512 +TIMESTAMP = 1024 +SET = 2048 +PART_KEY = 16384 +GROUP = 32767 +UNIQUE = 65536 diff --git a/lib/pymysql/constants/FLAG.pyc b/lib/pymysql/constants/FLAG.pyc new file mode 100644 index 0000000000000000000000000000000000000000..16cbdbf0c4bd3b4fb27df9d5e93de4472626574d GIT binary patch literal 519 zcmZ`#J5R$f7`!xnKluR+jGf5Bh)`2-tBAx2X*|>e73x<+L?1xR(24$M#0;NPBqkjB za(6!6XW9MiwGUr|WQpJ9@PEX+xMv_hGdj=?r~+L9xzH}C3S9-&plhHybRE=yZh)H5 zO;8KE1!_aLK^^E0s0-Z%^`Lv8K6D>6z-)NJBXT=1uUM#BXj&)_&MX^QI9LD&b8s*R z2Xk;Rw>QndKP=;8IUI1%*ajJA3#r1;G*~2Qu(%a-(`K$@aHm8myDTFWWDe=>+oL*ydn#L+AJCD~IvWGt?E?9c1SiKeA<7VkCceL_e_U37~^)~d(bh9sB k*X(Z#^RP9AHwpdeIVbEBTyA#szFu9~_bpBt>dyb)56cZ*9{>OV literal 0 HcmV?d00001 diff --git a/lib/pymysql/constants/SERVER_STATUS.py b/lib/pymysql/constants/SERVER_STATUS.py new file mode 100644 index 0000000..010f542 --- /dev/null +++ b/lib/pymysql/constants/SERVER_STATUS.py @@ -0,0 +1,12 @@ + +SERVER_STATUS_IN_TRANS = 1 +SERVER_STATUS_AUTOCOMMIT = 2 +SERVER_MORE_RESULTS_EXISTS = 8 +SERVER_QUERY_NO_GOOD_INDEX_USED = 16 +SERVER_QUERY_NO_INDEX_USED = 32 +SERVER_STATUS_CURSOR_EXISTS = 64 +SERVER_STATUS_LAST_ROW_SENT = 128 +SERVER_STATUS_DB_DROPPED = 256 +SERVER_STATUS_NO_BACKSLASH_ESCAPES = 512 +SERVER_STATUS_METADATA_CHANGED = 1024 + diff --git a/lib/pymysql/constants/SERVER_STATUS.pyc b/lib/pymysql/constants/SERVER_STATUS.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a3170fdce34b60f758958640f88d9a4ce921f816 GIT binary patch literal 597 zcmZvZ%}>HG7{=f64aR6Z7^8_APn_I8poX$FKxFG|JH=iaLopH=sGA3F{LjX_ZxeLr zY|~#qo+nS=wB?WO*6MR78pFCdICpTQ76w2e9Z(LK5~vcGGN>|`3aAR0DyS-$8mJnW zI;c9B2B-#@Ca5Nu7Krv1hD>ebv}Dn+*tIyd=vb^Q06kMc&lD;EVY`Kg**-#0eoMI) zlE_%-L8v7sp~wyj5{V`ASP%?kc9@F+<5Y7h;-M6pjs`-C>?D_OV#@Dz$aIe}AJct0 z(y^faX2g$YLq5tQ)|GiN7mR;jQPhV-NX^-u7BrOql<#-7&sh}V-DibxEU-(wYk?ts zO@&7yDzf8(EufP4L=x@wN!X))8y%1%y~M2>r<1qTeN4vgcwr{)%QAaf%-zI1<1$&M luQNQKr`f|iOWj|Oe~woBe;3KZyw4_A_CwP>M9ulzzW|Dwh>ZXM literal 0 HcmV?d00001 diff --git a/lib/pymysql/constants/__init__.py b/lib/pymysql/constants/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lib/pymysql/constants/__init__.pyc b/lib/pymysql/constants/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b2f26084d2deb0aa99e651101f40b35c4586a383 GIT binary patch literal 143 zcmZSn%*)mAl|LYv0SXv_v;z 2 + +try: + set +except NameError: + try: + from sets import BaseSet as set + except ImportError: + from sets import Set as set + +ESCAPE_REGEX = re.compile(r"[\0\n\r\032\'\"\\]") +ESCAPE_MAP = {'\0': '\\0', '\n': '\\n', '\r': '\\r', '\032': '\\Z', + '\'': '\\\'', '"': '\\"', '\\': '\\\\'} + +def escape_item(val, charset): + if type(val) in [tuple, list, set]: + return escape_sequence(val, charset) + if type(val) is dict: + return escape_dict(val, charset) + if PYTHON3 and hasattr(val, "decode") and not isinstance(val, unicode): + # deal with py3k bytes + val = val.decode(charset) + encoder = encoders[type(val)] + val = encoder(val) + if type(val) in [str, int]: + return val + val = val.encode(charset) + return val + +def escape_dict(val, charset): + n = {} + for k, v in val.items(): + quoted = escape_item(v, charset) + n[k] = quoted + return n + +def escape_sequence(val, charset): + n = [] + for item in val: + quoted = escape_item(item, charset) + n.append(quoted) + return "(" + ",".join(n) + ")" + +def escape_set(val, charset): + val = map(lambda x: escape_item(x, charset), val) + return ','.join(val) + +def escape_bool(value): + return str(int(value)) + +def escape_object(value): + return str(value) + +def escape_int(value): + return value + +escape_long = escape_object + +def escape_float(value): + return ('%.15g' % value) + +def escape_string(value): + return ("'%s'" % ESCAPE_REGEX.sub( + lambda match: ESCAPE_MAP.get(match.group(0)), value)) + +def escape_unicode(value): + return escape_string(value) + +def escape_None(value): + return 'NULL' + +def escape_timedelta(obj): + seconds = int(obj.seconds) % 60 + minutes = int(obj.seconds // 60) % 60 + hours = int(obj.seconds // 3600) % 24 + int(obj.days) * 24 + return escape_string('%02d:%02d:%02d' % (hours, minutes, seconds)) + +def escape_time(obj): + s = "%02d:%02d:%02d" % (int(obj.hour), int(obj.minute), + int(obj.second)) + if obj.microsecond: + s += ".%f" % obj.microsecond + + return escape_string(s) + +def escape_datetime(obj): + return escape_string(obj.strftime("%Y-%m-%d %H:%M:%S")) + +def escape_date(obj): + return escape_string(obj.strftime("%Y-%m-%d")) + +def escape_struct_time(obj): + return escape_datetime(datetime.datetime(*obj[:6])) + +def convert_datetime(connection, field, obj): + """Returns a DATETIME or TIMESTAMP column value as a datetime object: + + >>> datetime_or_None('2007-02-25 23:06:20') + datetime.datetime(2007, 2, 25, 23, 6, 20) + >>> datetime_or_None('2007-02-25T23:06:20') + datetime.datetime(2007, 2, 25, 23, 6, 20) + + Illegal values are returned as None: + + >>> datetime_or_None('2007-02-31T23:06:20') is None + True + >>> datetime_or_None('0000-00-00 00:00:00') is None + True + + """ + if not isinstance(obj, unicode): + obj = obj.decode(connection.charset) + if ' ' in obj: + sep = ' ' + elif 'T' in obj: + sep = 'T' + else: + return convert_date(connection, field, obj) + + try: + ymd, hms = obj.split(sep, 1) + return datetime.datetime(*[ int(x) for x in ymd.split('-')+hms.split(':') ]) + except ValueError: + return convert_date(connection, field, obj) + +def convert_timedelta(connection, field, obj): + """Returns a TIME column as a timedelta object: + + >>> timedelta_or_None('25:06:17') + datetime.timedelta(1, 3977) + >>> timedelta_or_None('-25:06:17') + datetime.timedelta(-2, 83177) + + Illegal values are returned as None: + + >>> timedelta_or_None('random crap') is None + True + + Note that MySQL always returns TIME columns as (+|-)HH:MM:SS, but + can accept values as (+|-)DD HH:MM:SS. The latter format will not + be parsed correctly by this function. + """ + try: + microseconds = 0 + if not isinstance(obj, unicode): + obj = obj.decode(connection.charset) + if "." in obj: + (obj, tail) = obj.split('.') + microseconds = int(tail) + hours, minutes, seconds = obj.split(':') + tdelta = datetime.timedelta( + hours = int(hours), + minutes = int(minutes), + seconds = int(seconds), + microseconds = microseconds + ) + return tdelta + except ValueError: + return None + +def convert_time(connection, field, obj): + """Returns a TIME column as a time object: + + >>> time_or_None('15:06:17') + datetime.time(15, 6, 17) + + Illegal values are returned as None: + + >>> time_or_None('-25:06:17') is None + True + >>> time_or_None('random crap') is None + True + + Note that MySQL always returns TIME columns as (+|-)HH:MM:SS, but + can accept values as (+|-)DD HH:MM:SS. The latter format will not + be parsed correctly by this function. + + Also note that MySQL's TIME column corresponds more closely to + Python's timedelta and not time. However if you want TIME columns + to be treated as time-of-day and not a time offset, then you can + use set this function as the converter for FIELD_TYPE.TIME. + """ + try: + microseconds = 0 + if "." in obj: + (obj, tail) = obj.split('.') + microseconds = int(tail) + hours, minutes, seconds = obj.split(':') + return datetime.time(hour=int(hours), minute=int(minutes), + second=int(seconds), microsecond=microseconds) + except ValueError: + return None + +def convert_date(connection, field, obj): + """Returns a DATE column as a date object: + + >>> date_or_None('2007-02-26') + datetime.date(2007, 2, 26) + + Illegal values are returned as None: + + >>> date_or_None('2007-02-31') is None + True + >>> date_or_None('0000-00-00') is None + True + + """ + try: + if not isinstance(obj, unicode): + obj = obj.decode(connection.charset) + return datetime.date(*[ int(x) for x in obj.split('-', 2) ]) + except ValueError: + return None + +def convert_mysql_timestamp(connection, field, timestamp): + """Convert a MySQL TIMESTAMP to a Timestamp object. + + MySQL >= 4.1 returns TIMESTAMP in the same format as DATETIME: + + >>> mysql_timestamp_converter('2007-02-25 22:32:17') + datetime.datetime(2007, 2, 25, 22, 32, 17) + + MySQL < 4.1 uses a big string of numbers: + + >>> mysql_timestamp_converter('20070225223217') + datetime.datetime(2007, 2, 25, 22, 32, 17) + + Illegal values are returned as None: + + >>> mysql_timestamp_converter('2007-02-31 22:32:17') is None + True + >>> mysql_timestamp_converter('00000000000000') is None + True + + """ + if not isinstance(timestamp, unicode): + timestamp = timestamp.decode(connection.charset) + + if timestamp[4] == '-': + return convert_datetime(connection, field, timestamp) + timestamp += "0"*(14-len(timestamp)) # padding + year, month, day, hour, minute, second = \ + int(timestamp[:4]), int(timestamp[4:6]), int(timestamp[6:8]), \ + int(timestamp[8:10]), int(timestamp[10:12]), int(timestamp[12:14]) + try: + return datetime.datetime(year, month, day, hour, minute, second) + except ValueError: + return None + +def convert_set(s): + return set(s.split(",")) + +def convert_bit(connection, field, b): + #b = "\x00" * (8 - len(b)) + b # pad w/ zeroes + #return struct.unpack(">Q", b)[0] + # + # the snippet above is right, but MySQLdb doesn't process bits, + # so we shouldn't either + return b + +def convert_characters(connection, field, data): + field_charset = charset_by_id(field.charsetnr).name + if field.flags & FLAG.SET: + return convert_set(data.decode(field_charset)) + if field.flags & FLAG.BINARY: + return data + + if connection.use_unicode: + data = data.decode(field_charset) + elif connection.charset != field_charset: + data = data.decode(field_charset) + data = data.encode(connection.charset) + return data + +def convert_int(connection, field, data): + return int(data) + +def convert_long(connection, field, data): + return long(data) + +def convert_float(connection, field, data): + return float(data) + +encoders = { + bool: escape_bool, + int: escape_int, + long: escape_long, + float: escape_float, + str: escape_string, + unicode: escape_unicode, + tuple: escape_sequence, + list:escape_sequence, + set:escape_sequence, + dict:escape_dict, + type(None):escape_None, + datetime.date: escape_date, + datetime.datetime : escape_datetime, + datetime.timedelta : escape_timedelta, + datetime.time : escape_time, + time.struct_time : escape_struct_time, + } + +decoders = { + FIELD_TYPE.BIT: convert_bit, + FIELD_TYPE.TINY: convert_int, + FIELD_TYPE.SHORT: convert_int, + FIELD_TYPE.LONG: convert_long, + FIELD_TYPE.FLOAT: convert_float, + FIELD_TYPE.DOUBLE: convert_float, + FIELD_TYPE.DECIMAL: convert_float, + FIELD_TYPE.NEWDECIMAL: convert_float, + FIELD_TYPE.LONGLONG: convert_long, + FIELD_TYPE.INT24: convert_int, + FIELD_TYPE.YEAR: convert_int, + FIELD_TYPE.TIMESTAMP: convert_mysql_timestamp, + FIELD_TYPE.DATETIME: convert_datetime, + FIELD_TYPE.TIME: convert_timedelta, + FIELD_TYPE.DATE: convert_date, + FIELD_TYPE.SET: convert_set, + FIELD_TYPE.BLOB: convert_characters, + FIELD_TYPE.TINY_BLOB: convert_characters, + FIELD_TYPE.MEDIUM_BLOB: convert_characters, + FIELD_TYPE.LONG_BLOB: convert_characters, + FIELD_TYPE.STRING: convert_characters, + FIELD_TYPE.VAR_STRING: convert_characters, + FIELD_TYPE.VARCHAR: convert_characters, + #FIELD_TYPE.BLOB: str, + #FIELD_TYPE.STRING: str, + #FIELD_TYPE.VAR_STRING: str, + #FIELD_TYPE.VARCHAR: str + } +conversions = decoders # for MySQLdb compatibility + +try: + # python version > 2.3 + from decimal import Decimal + def convert_decimal(connection, field, data): + data = data.decode(connection.charset) + return Decimal(data) + decoders[FIELD_TYPE.DECIMAL] = convert_decimal + decoders[FIELD_TYPE.NEWDECIMAL] = convert_decimal + + def escape_decimal(obj): + return unicode(obj) + encoders[Decimal] = escape_decimal + +except ImportError: + pass diff --git a/lib/pymysql/converters.pyc b/lib/pymysql/converters.pyc new file mode 100644 index 0000000000000000000000000000000000000000..380f20d6458bd91f1a8cfcb5a18a3bacc945c5aa GIT binary patch literal 12688 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 Ru`}Imb*DO0hf>|v{{alJPbUBX literal 0 HcmV?d00001 diff --git a/lib/pymysql/cursors.py b/lib/pymysql/cursors.py new file mode 100644 index 0000000..f9775f5 --- /dev/null +++ b/lib/pymysql/cursors.py @@ -0,0 +1,410 @@ +# -*- coding: utf-8 -*- +import struct +import re + +try: + import cStringIO as StringIO +except ImportError: + import StringIO + +from err import Warning, Error, InterfaceError, DataError, \ + DatabaseError, OperationalError, IntegrityError, InternalError, \ + NotSupportedError, ProgrammingError + +insert_values = re.compile(r'\svalues\s*(\(.+\))', re.IGNORECASE) + +class Cursor(object): + ''' + This is the object you use to interact with the database. + ''' + def __init__(self, connection): + ''' + Do not create an instance of a Cursor yourself. Call + connections.Connection.cursor(). + ''' + from weakref import proxy + self.connection = proxy(connection) + self.description = None + self.rownumber = 0 + self.rowcount = -1 + self.arraysize = 1 + self._executed = None + self.messages = [] + self.errorhandler = connection.errorhandler + self._has_next = None + self._rows = () + + def __del__(self): + ''' + When this gets GC'd close it. + ''' + self.close() + + def close(self): + ''' + Closing a cursor just exhausts all remaining data. + ''' + if not self.connection: + return + try: + while self.nextset(): + pass + except: + pass + + self.connection = None + + def _get_db(self): + if not self.connection: + self.errorhandler(self, ProgrammingError, "cursor closed") + return self.connection + + def _check_executed(self): + if not self._executed: + self.errorhandler(self, ProgrammingError, "execute() first") + + def setinputsizes(self, *args): + """Does nothing, required by DB API.""" + + def setoutputsizes(self, *args): + """Does nothing, required by DB API.""" + + def nextset(self): + ''' Get the next query set ''' + if self._executed: + self.fetchall() + del self.messages[:] + + if not self._has_next: + return None + connection = self._get_db() + connection.next_result() + self._do_get_result() + return True + + def execute(self, query, args=None): + ''' Execute a query ''' + from sys import exc_info + + conn = self._get_db() + charset = conn.charset + del self.messages[:] + + # TODO: make sure that conn.escape is correct + + if isinstance(query, unicode): + query = query.encode(charset) + + if args is not None: + if isinstance(args, tuple) or isinstance(args, list): + escaped_args = tuple(conn.escape(arg) for arg in args) + elif isinstance(args, dict): + escaped_args = dict((key, conn.escape(val)) for (key, val) in args.items()) + else: + #If it's not a dictionary let's try escaping it anyways. + #Worst case it will throw a Value error + escaped_args = conn.escape(args) + + query = query % escaped_args + + result = 0 + try: + result = self._query(query) + except: + exc, value, tb = exc_info() + del tb + self.messages.append((exc,value)) + self.errorhandler(self, exc, value) + + self._executed = query + return result + + def executemany(self, query, args): + ''' Run several data against one query ''' + del self.messages[:] + #conn = self._get_db() + if not args: + return + #charset = conn.charset + #if isinstance(query, unicode): + # query = query.encode(charset) + + self.rowcount = sum([ self.execute(query, arg) for arg in args ]) + return self.rowcount + + + def callproc(self, procname, args=()): + """Execute stored procedure procname with args + + procname -- string, name of procedure to execute on server + + args -- Sequence of parameters to use with procedure + + Returns the original args. + + Compatibility warning: PEP-249 specifies that any modified + parameters must be returned. This is currently impossible + as they are only available by storing them in a server + variable and then retrieved by a query. Since stored + procedures return zero or more result sets, there is no + reliable way to get at OUT or INOUT parameters via callproc. + The server variables are named @_procname_n, where procname + is the parameter above and n is the position of the parameter + (from zero). Once all result sets generated by the procedure + have been fetched, you can issue a SELECT @_procname_0, ... + query using .execute() to get any OUT or INOUT values. + + Compatibility warning: The act of calling a stored procedure + itself creates an empty result set. This appears after any + result sets generated by the procedure. This is non-standard + behavior with respect to the DB-API. Be sure to use nextset() + to advance through all result sets; otherwise you may get + disconnected. + """ + conn = self._get_db() + for index, arg in enumerate(args): + q = "SET @_%s_%d=%s" % (procname, index, conn.escape(arg)) + if isinstance(q, unicode): + q = q.encode(conn.charset) + self._query(q) + self.nextset() + + q = "CALL %s(%s)" % (procname, + ','.join(['@_%s_%d' % (procname, i) + for i in range(len(args))])) + if isinstance(q, unicode): + q = q.encode(conn.charset) + self._query(q) + self._executed = q + + return args + + def fetchone(self): + ''' Fetch the next row ''' + self._check_executed() + if self._rows is None or self.rownumber >= len(self._rows): + return None + result = self._rows[self.rownumber] + self.rownumber += 1 + return result + + def fetchmany(self, size=None): + ''' Fetch several rows ''' + self._check_executed() + end = self.rownumber + (size or self.arraysize) + result = self._rows[self.rownumber:end] + if self._rows is None: + return None + self.rownumber = min(end, len(self._rows)) + return result + + def fetchall(self): + ''' Fetch all the rows ''' + self._check_executed() + if self._rows is None: + return None + if self.rownumber: + result = self._rows[self.rownumber:] + else: + result = self._rows + self.rownumber = len(self._rows) + return result + + def scroll(self, value, mode='relative'): + self._check_executed() + if mode == 'relative': + r = self.rownumber + value + elif mode == 'absolute': + r = value + else: + self.errorhandler(self, ProgrammingError, + "unknown scroll mode %s" % mode) + + if r < 0 or r >= len(self._rows): + self.errorhandler(self, IndexError, "out of range") + self.rownumber = r + + def _query(self, q): + conn = self._get_db() + self._last_executed = q + conn.query(q) + self._do_get_result() + return self.rowcount + + def _do_get_result(self): + conn = self._get_db() + self.rowcount = conn._result.affected_rows + + self.rownumber = 0 + self.description = conn._result.description + self.lastrowid = conn._result.insert_id + self._rows = conn._result.rows + self._has_next = conn._result.has_next + + def __iter__(self): + return iter(self.fetchone, None) + + Warning = Warning + Error = Error + InterfaceError = InterfaceError + DatabaseError = DatabaseError + DataError = DataError + OperationalError = OperationalError + IntegrityError = IntegrityError + InternalError = InternalError + ProgrammingError = ProgrammingError + NotSupportedError = NotSupportedError + +class DictCursor(Cursor): + """A cursor which returns results as a dictionary""" + + def execute(self, query, args=None): + result = super(DictCursor, self).execute(query, args) + if self.description: + self._fields = [ field[0] for field in self.description ] + return result + + def fetchone(self): + ''' Fetch the next row ''' + self._check_executed() + if self._rows is None or self.rownumber >= len(self._rows): + return None + result = dict(zip(self._fields, self._rows[self.rownumber])) + self.rownumber += 1 + return result + + def fetchmany(self, size=None): + ''' Fetch several rows ''' + self._check_executed() + if self._rows is None: + return None + end = self.rownumber + (size or self.arraysize) + result = [ dict(zip(self._fields, r)) for r in self._rows[self.rownumber:end] ] + self.rownumber = min(end, len(self._rows)) + return tuple(result) + + def fetchall(self): + ''' Fetch all the rows ''' + self._check_executed() + if self._rows is None: + return None + if self.rownumber: + result = [ dict(zip(self._fields, r)) for r in self._rows[self.rownumber:] ] + else: + result = [ dict(zip(self._fields, r)) for r in self._rows ] + self.rownumber = len(self._rows) + return tuple(result) + +class SSCursor(Cursor): + """ + Unbuffered Cursor, mainly useful for queries that return a lot of data, + or for connections to remote servers over a slow network. + + Instead of copying every row of data into a buffer, this will fetch + rows as needed. The upside of this, is the client uses much less memory, + and rows are returned much faster when traveling over a slow network, + or if the result set is very big. + + There are limitations, though. The MySQL protocol doesn't support + returning the total number of rows, so the only way to tell how many rows + there are is to iterate over every row returned. Also, it currently isn't + possible to scroll backwards, as only the current row is held in memory. + """ + + def close(self): + conn = self._get_db() + conn._result._finish_unbuffered_query() + + try: + if self._has_next: + while self.nextset(): pass + except: pass + + def _query(self, q): + conn = self._get_db() + self._last_executed = q + conn.query(q, unbuffered=True) + self._do_get_result() + return self.rowcount + + def read_next(self): + """ Read next row """ + + conn = self._get_db() + conn._result._read_rowdata_packet_unbuffered() + return conn._result.rows + + def fetchone(self): + """ Fetch next row """ + + self._check_executed() + row = self.read_next() + if row is None: + return None + self.rownumber += 1 + return row + + def fetchall(self): + """ + Fetch all, as per MySQLdb. Pretty useless for large queries, as + it is buffered. See fetchall_unbuffered(), if you want an unbuffered + generator version of this method. + """ + + rows = [] + while True: + row = self.fetchone() + if row is None: + break + rows.append(row) + return tuple(rows) + + def fetchall_unbuffered(self): + """ + Fetch all, implemented as a generator, which isn't to standard, + however, it doesn't make sense to return everything in a list, as that + would use ridiculous memory for large result sets. + """ + + row = self.fetchone() + while row is not None: + yield row + row = self.fetchone() + + def fetchmany(self, size=None): + """ Fetch many """ + + self._check_executed() + if size is None: + size = self.arraysize + + rows = [] + for i in range(0, size): + row = self.read_next() + if row is None: + break + rows.append(row) + self.rownumber += 1 + return tuple(rows) + + def scroll(self, value, mode='relative'): + self._check_executed() + if not mode == 'relative' and not mode == 'absolute': + self.errorhandler(self, ProgrammingError, + "unknown scroll mode %s" % mode) + + if mode == 'relative': + if value < 0: + self.errorhandler(self, NotSupportedError, + "Backwards scrolling not supported by this cursor") + + for i in range(0, value): self.read_next() + self.rownumber += value + else: + if value < self.rownumber: + self.errorhandler(self, NotSupportedError, + "Backwards scrolling not supported by this cursor") + + end = value - self.rownumber + for i in range(0, end): self.read_next() + self.rownumber = value diff --git a/lib/pymysql/cursors.pyc b/lib/pymysql/cursors.pyc new file mode 100644 index 0000000000000000000000000000000000000000..80fef013fd7ed5e532b3e337fd4cd2c3053863e1 GIT binary patch literal 14523 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 tuple) + c.execute("SELECT * from dictcursor where name='bob'") + r = c.fetchall() + self.assertEqual((bob,),r,"fetch a 1 row result via fetchall failed via DictCursor") + # same test again but iterate over the + c.execute("SELECT * from dictcursor where name='bob'") + for r in c: + self.assertEqual(bob, r,"fetch a 1 row result via iteration failed via DictCursor") + # get all 3 row via fetchall + c.execute("SELECT * from dictcursor") + r = c.fetchall() + self.assertEqual((bob,jim,fred), r, "fetchall failed via DictCursor") + #same test again but do a list comprehension + c.execute("SELECT * from dictcursor") + r = [x for x in c] + self.assertEqual([bob,jim,fred], r, "list comprehension failed via DictCursor") + # get all 2 row via fetchmany + c.execute("SELECT * from dictcursor") + r = c.fetchmany(2) + self.assertEqual((bob,jim), r, "fetchmany failed via DictCursor") + finally: + c.execute("drop table dictcursor") + +__all__ = ["TestDictCursor"] + +if __name__ == "__main__": + import unittest + unittest.main() diff --git a/lib/pymysql/tests/test_SSCursor.py b/lib/pymysql/tests/test_SSCursor.py new file mode 100644 index 0000000..a0e3caf --- /dev/null +++ b/lib/pymysql/tests/test_SSCursor.py @@ -0,0 +1,100 @@ +import sys + +try: + from pymysql.tests import base + import pymysql.cursors +except: + # For local testing from top-level directory, without installing + sys.path.append('../pymysql') + from pymysql.tests import base + import pymysql.cursors + +class TestSSCursor(base.PyMySQLTestCase): + def test_SSCursor(self): + affected_rows = 18446744073709551615 + + conn = self.connections[0] + data = [ + ('America', '', 'America/Jamaica'), + ('America', '', 'America/Los_Angeles'), + ('America', '', 'America/Lima'), + ('America', '', 'America/New_York'), + ('America', '', 'America/Menominee'), + ('America', '', 'America/Havana'), + ('America', '', 'America/El_Salvador'), + ('America', '', 'America/Costa_Rica'), + ('America', '', 'America/Denver'), + ('America', '', 'America/Detroit'),] + + try: + cursor = conn.cursor(pymysql.cursors.SSCursor) + + # Create table + cursor.execute(('CREATE TABLE tz_data (' + 'region VARCHAR(64),' + 'zone VARCHAR(64),' + 'name VARCHAR(64))')) + + # Test INSERT + for i in data: + cursor.execute('INSERT INTO tz_data VALUES (%s, %s, %s)', i) + self.assertEqual(conn.affected_rows(), 1, 'affected_rows does not match') + conn.commit() + + # Test fetchone() + iter = 0 + cursor.execute('SELECT * FROM tz_data') + while True: + row = cursor.fetchone() + if row is None: + break + iter += 1 + + # Test cursor.rowcount + self.assertEqual(cursor.rowcount, affected_rows, + 'cursor.rowcount != %s' % (str(affected_rows))) + + # Test cursor.rownumber + self.assertEqual(cursor.rownumber, iter, + 'cursor.rowcount != %s' % (str(iter))) + + # Test row came out the same as it went in + self.assertEqual((row in data), True, + 'Row not found in source data') + + # Test fetchall + cursor.execute('SELECT * FROM tz_data') + self.assertEqual(len(cursor.fetchall()), len(data), + 'fetchall failed. Number of rows does not match') + + # Test fetchmany + cursor.execute('SELECT * FROM tz_data') + self.assertEqual(len(cursor.fetchmany(2)), 2, + 'fetchmany failed. Number of rows does not match') + + # So MySQLdb won't throw "Commands out of sync" + while True: + res = cursor.fetchone() + if res is None: + break + + # Test update, affected_rows() + cursor.execute('UPDATE tz_data SET zone = %s', ['Foo']) + conn.commit() + self.assertEqual(cursor.rowcount, len(data), + 'Update failed. affected_rows != %s' % (str(len(data)))) + + # Test executemany + cursor.executemany('INSERT INTO tz_data VALUES (%s, %s, %s)', data) + self.assertEqual(cursor.rowcount, len(data), + 'executemany failed. cursor.rowcount != %s' % (str(len(data)))) + + finally: + cursor.execute('DROP TABLE tz_data') + cursor.close() + +__all__ = ["TestSSCursor"] + +if __name__ == "__main__": + import unittest + unittest.main() diff --git a/lib/pymysql/tests/test_basic.py b/lib/pymysql/tests/test_basic.py new file mode 100644 index 0000000..fb7a30f --- /dev/null +++ b/lib/pymysql/tests/test_basic.py @@ -0,0 +1,213 @@ +from pymysql.tests import base +from pymysql import util + +import time +import datetime + +class TestConversion(base.PyMySQLTestCase): + def test_datatypes(self): + """ test every data type """ + conn = self.connections[0] + c = conn.cursor() + c.execute("create table test_datatypes (b bit, i int, l bigint, f real, s varchar(32), u varchar(32), bb blob, d date, dt datetime, ts timestamp, td time, t time, st datetime)") + try: + # insert values + v = (True, -3, 123456789012, 5.7, "hello'\" world", u"Espa\xc3\xb1ol", "binary\x00data".encode(conn.charset), datetime.date(1988,2,2), datetime.datetime.now(), datetime.timedelta(5,6), datetime.time(16,32), time.localtime()) + c.execute("insert into test_datatypes (b,i,l,f,s,u,bb,d,dt,td,t,st) values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", v) + c.execute("select b,i,l,f,s,u,bb,d,dt,td,t,st from test_datatypes") + r = c.fetchone() + self.assertEqual(util.int2byte(1), r[0]) + self.assertEqual(v[1:8], r[1:8]) + # mysql throws away microseconds so we need to check datetimes + # specially. additionally times are turned into timedeltas. + self.assertEqual(datetime.datetime(*v[8].timetuple()[:6]), r[8]) + self.assertEqual(v[9], r[9]) # just timedeltas + self.assertEqual(datetime.timedelta(0, 60 * (v[10].hour * 60 + v[10].minute)), r[10]) + self.assertEqual(datetime.datetime(*v[-1][:6]), r[-1]) + + c.execute("delete from test_datatypes") + + # check nulls + c.execute("insert into test_datatypes (b,i,l,f,s,u,bb,d,dt,td,t,st) values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", [None] * 12) + c.execute("select b,i,l,f,s,u,bb,d,dt,td,t,st from test_datatypes") + r = c.fetchone() + self.assertEqual(tuple([None] * 12), r) + + c.execute("delete from test_datatypes") + + # check sequence type + c.execute("insert into test_datatypes (i, l) values (2,4), (6,8), (10,12)") + c.execute("select l from test_datatypes where i in %s order by i", ((2,6),)) + r = c.fetchall() + self.assertEqual(((4,),(8,)), r) + finally: + c.execute("drop table test_datatypes") + + def test_dict(self): + """ test dict escaping """ + conn = self.connections[0] + c = conn.cursor() + c.execute("create table test_dict (a integer, b integer, c integer)") + try: + c.execute("insert into test_dict (a,b,c) values (%(a)s, %(b)s, %(c)s)", {"a":1,"b":2,"c":3}) + c.execute("select a,b,c from test_dict") + self.assertEqual((1,2,3), c.fetchone()) + finally: + c.execute("drop table test_dict") + + def test_string(self): + conn = self.connections[0] + c = conn.cursor() + c.execute("create table test_dict (a text)") + test_value = "I am a test string" + try: + c.execute("insert into test_dict (a) values (%s)", test_value) + c.execute("select a from test_dict") + self.assertEqual((test_value,), c.fetchone()) + finally: + c.execute("drop table test_dict") + + def test_integer(self): + conn = self.connections[0] + c = conn.cursor() + c.execute("create table test_dict (a integer)") + test_value = 12345 + try: + c.execute("insert into test_dict (a) values (%s)", test_value) + c.execute("select a from test_dict") + self.assertEqual((test_value,), c.fetchone()) + finally: + c.execute("drop table test_dict") + + + def test_big_blob(self): + """ test tons of data """ + conn = self.connections[0] + c = conn.cursor() + c.execute("create table test_big_blob (b blob)") + try: + data = "pymysql" * 1024 + c.execute("insert into test_big_blob (b) values (%s)", (data,)) + c.execute("select b from test_big_blob") + self.assertEqual(data.encode(conn.charset), c.fetchone()[0]) + finally: + c.execute("drop table test_big_blob") + + def test_untyped(self): + """ test conversion of null, empty string """ + conn = self.connections[0] + c = conn.cursor() + c.execute("select null,''") + self.assertEqual((None,u''), c.fetchone()) + c.execute("select '',null") + self.assertEqual((u'',None), c.fetchone()) + + def test_datetime(self): + """ test conversion of null, empty string """ + conn = self.connections[0] + c = conn.cursor() + c.execute("select time('12:30'), time('23:12:59'), time('23:12:59.05100')") + self.assertEqual((datetime.timedelta(0, 45000), + datetime.timedelta(0, 83579), + datetime.timedelta(0, 83579, 51000)), + c.fetchone()) + + +class TestCursor(base.PyMySQLTestCase): + # this test case does not work quite right yet, however, + # we substitute in None for the erroneous field which is + # compatible with the DB-API 2.0 spec and has not broken + # any unit tests for anything we've tried. + + #def test_description(self): + # """ test description attribute """ + # # result is from MySQLdb module + # r = (('Host', 254, 11, 60, 60, 0, 0), + # ('User', 254, 16, 16, 16, 0, 0), + # ('Password', 254, 41, 41, 41, 0, 0), + # ('Select_priv', 254, 1, 1, 1, 0, 0), + # ('Insert_priv', 254, 1, 1, 1, 0, 0), + # ('Update_priv', 254, 1, 1, 1, 0, 0), + # ('Delete_priv', 254, 1, 1, 1, 0, 0), + # ('Create_priv', 254, 1, 1, 1, 0, 0), + # ('Drop_priv', 254, 1, 1, 1, 0, 0), + # ('Reload_priv', 254, 1, 1, 1, 0, 0), + # ('Shutdown_priv', 254, 1, 1, 1, 0, 0), + # ('Process_priv', 254, 1, 1, 1, 0, 0), + # ('File_priv', 254, 1, 1, 1, 0, 0), + # ('Grant_priv', 254, 1, 1, 1, 0, 0), + # ('References_priv', 254, 1, 1, 1, 0, 0), + # ('Index_priv', 254, 1, 1, 1, 0, 0), + # ('Alter_priv', 254, 1, 1, 1, 0, 0), + # ('Show_db_priv', 254, 1, 1, 1, 0, 0), + # ('Super_priv', 254, 1, 1, 1, 0, 0), + # ('Create_tmp_table_priv', 254, 1, 1, 1, 0, 0), + # ('Lock_tables_priv', 254, 1, 1, 1, 0, 0), + # ('Execute_priv', 254, 1, 1, 1, 0, 0), + # ('Repl_slave_priv', 254, 1, 1, 1, 0, 0), + # ('Repl_client_priv', 254, 1, 1, 1, 0, 0), + # ('Create_view_priv', 254, 1, 1, 1, 0, 0), + # ('Show_view_priv', 254, 1, 1, 1, 0, 0), + # ('Create_routine_priv', 254, 1, 1, 1, 0, 0), + # ('Alter_routine_priv', 254, 1, 1, 1, 0, 0), + # ('Create_user_priv', 254, 1, 1, 1, 0, 0), + # ('Event_priv', 254, 1, 1, 1, 0, 0), + # ('Trigger_priv', 254, 1, 1, 1, 0, 0), + # ('ssl_type', 254, 0, 9, 9, 0, 0), + # ('ssl_cipher', 252, 0, 65535, 65535, 0, 0), + # ('x509_issuer', 252, 0, 65535, 65535, 0, 0), + # ('x509_subject', 252, 0, 65535, 65535, 0, 0), + # ('max_questions', 3, 1, 11, 11, 0, 0), + # ('max_updates', 3, 1, 11, 11, 0, 0), + # ('max_connections', 3, 1, 11, 11, 0, 0), + # ('max_user_connections', 3, 1, 11, 11, 0, 0)) + # conn = self.connections[0] + # c = conn.cursor() + # c.execute("select * from mysql.user") + # + # self.assertEqual(r, c.description) + + def test_fetch_no_result(self): + """ test a fetchone() with no rows """ + conn = self.connections[0] + c = conn.cursor() + c.execute("create table test_nr (b varchar(32))") + try: + data = "pymysql" + c.execute("insert into test_nr (b) values (%s)", (data,)) + self.assertEqual(None, c.fetchone()) + finally: + c.execute("drop table test_nr") + + def test_aggregates(self): + """ test aggregate functions """ + conn = self.connections[0] + c = conn.cursor() + try: + c.execute('create table test_aggregates (i integer)') + for i in xrange(0, 10): + c.execute('insert into test_aggregates (i) values (%s)', (i,)) + c.execute('select sum(i) from test_aggregates') + r, = c.fetchone() + self.assertEqual(sum(range(0,10)), r) + finally: + c.execute('drop table test_aggregates') + + def test_single_tuple(self): + """ test a single tuple """ + conn = self.connections[0] + c = conn.cursor() + try: + c.execute("create table mystuff (id integer primary key)") + c.execute("insert into mystuff (id) values (1)") + c.execute("insert into mystuff (id) values (2)") + c.execute("select id from mystuff where id in %s", ((1,),)) + self.assertEqual([(1,)], list(c.fetchall())) + finally: + c.execute("drop table mystuff") + +__all__ = ["TestConversion","TestCursor"] + +if __name__ == "__main__": + import unittest + unittest.main() diff --git a/lib/pymysql/tests/test_example.py b/lib/pymysql/tests/test_example.py new file mode 100644 index 0000000..2da05db --- /dev/null +++ b/lib/pymysql/tests/test_example.py @@ -0,0 +1,32 @@ +import pymysql +from pymysql.tests import base + +class TestExample(base.PyMySQLTestCase): + def test_example(self): + conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='mysql') + + + cur = conn.cursor() + + cur.execute("SELECT Host,User FROM user") + + # print cur.description + + # r = cur.fetchall() + # print r + # ...or... + u = False + + for r in cur.fetchall(): + u = u or conn.user in r + + self.assertTrue(u) + + cur.close() + conn.close() + +__all__ = ["TestExample"] + +if __name__ == "__main__": + import unittest + unittest.main() diff --git a/lib/pymysql/tests/test_issues.py b/lib/pymysql/tests/test_issues.py new file mode 100644 index 0000000..6f7fc3d --- /dev/null +++ b/lib/pymysql/tests/test_issues.py @@ -0,0 +1,278 @@ +import pymysql +from pymysql.tests import base +import unittest + +import sys + +try: + import imp + reload = imp.reload +except AttributeError: + pass + +import datetime + +# backwards compatibility: +if not hasattr(unittest, "skip"): + unittest.skip = lambda message: lambda f: f + +class TestOldIssues(base.PyMySQLTestCase): + def test_issue_3(self): + """ undefined methods datetime_or_None, date_or_None """ + conn = self.connections[0] + c = conn.cursor() + c.execute("create table issue3 (d date, t time, dt datetime, ts timestamp)") + try: + c.execute("insert into issue3 (d, t, dt, ts) values (%s,%s,%s,%s)", (None, None, None, None)) + c.execute("select d from issue3") + self.assertEqual(None, c.fetchone()[0]) + c.execute("select t from issue3") + self.assertEqual(None, c.fetchone()[0]) + c.execute("select dt from issue3") + self.assertEqual(None, c.fetchone()[0]) + c.execute("select ts from issue3") + self.assertTrue(isinstance(c.fetchone()[0], datetime.datetime)) + finally: + c.execute("drop table issue3") + + def test_issue_4(self): + """ can't retrieve TIMESTAMP fields """ + conn = self.connections[0] + c = conn.cursor() + c.execute("create table issue4 (ts timestamp)") + try: + c.execute("insert into issue4 (ts) values (now())") + c.execute("select ts from issue4") + self.assertTrue(isinstance(c.fetchone()[0], datetime.datetime)) + finally: + c.execute("drop table issue4") + + def test_issue_5(self): + """ query on information_schema.tables fails """ + con = self.connections[0] + cur = con.cursor() + cur.execute("select * from information_schema.tables") + + def test_issue_6(self): + """ exception: TypeError: ord() expected a character, but string of length 0 found """ + conn = pymysql.connect(host="localhost",user="root",passwd="",db="mysql") + c = conn.cursor() + c.execute("select * from user") + conn.close() + + def test_issue_8(self): + """ Primary Key and Index error when selecting data """ + conn = self.connections[0] + c = conn.cursor() + c.execute("""CREATE TABLE `test` (`station` int(10) NOT NULL DEFAULT '0', `dh` +datetime NOT NULL DEFAULT '0000-00-00 00:00:00', `echeance` int(1) NOT NULL +DEFAULT '0', `me` double DEFAULT NULL, `mo` double DEFAULT NULL, PRIMARY +KEY (`station`,`dh`,`echeance`)) ENGINE=MyISAM DEFAULT CHARSET=latin1;""") + try: + self.assertEqual(0, c.execute("SELECT * FROM test")) + c.execute("ALTER TABLE `test` ADD INDEX `idx_station` (`station`)") + self.assertEqual(0, c.execute("SELECT * FROM test")) + finally: + c.execute("drop table test") + + def test_issue_9(self): + """ sets DeprecationWarning in Python 2.6 """ + try: + reload(pymysql) + except DeprecationWarning: + self.fail() + + def test_issue_10(self): + """ Allocate a variable to return when the exception handler is permissive """ + conn = self.connections[0] + conn.errorhandler = lambda cursor, errorclass, errorvalue: None + cur = conn.cursor() + cur.execute( "create table t( n int )" ) + cur.execute( "create table t( n int )" ) + + def test_issue_13(self): + """ can't handle large result fields """ + conn = self.connections[0] + cur = conn.cursor() + try: + cur.execute("create table issue13 (t text)") + # ticket says 18k + size = 18*1024 + cur.execute("insert into issue13 (t) values (%s)", ("x" * size,)) + cur.execute("select t from issue13") + # use assertTrue so that obscenely huge error messages don't print + r = cur.fetchone()[0] + self.assertTrue("x" * size == r) + finally: + cur.execute("drop table issue13") + + def test_issue_14(self): + """ typo in converters.py """ + self.assertEqual('1', pymysql.converters.escape_item(1, "utf8")) + self.assertEqual('1', pymysql.converters.escape_item(1L, "utf8")) + + self.assertEqual('1', pymysql.converters.escape_object(1)) + self.assertEqual('1', pymysql.converters.escape_object(1L)) + + def test_issue_15(self): + """ query should be expanded before perform character encoding """ + conn = self.connections[0] + c = conn.cursor() + c.execute("create table issue15 (t varchar(32))") + try: + c.execute("insert into issue15 (t) values (%s)", (u'\xe4\xf6\xfc',)) + c.execute("select t from issue15") + self.assertEqual(u'\xe4\xf6\xfc', c.fetchone()[0]) + finally: + c.execute("drop table issue15") + + def test_issue_16(self): + """ Patch for string and tuple escaping """ + conn = self.connections[0] + c = conn.cursor() + c.execute("create table issue16 (name varchar(32) primary key, email varchar(32))") + try: + c.execute("insert into issue16 (name, email) values ('pete', 'floydophone')") + c.execute("select email from issue16 where name=%s", ("pete",)) + self.assertEqual("floydophone", c.fetchone()[0]) + finally: + c.execute("drop table issue16") + + @unittest.skip("test_issue_17() requires a custom, legacy MySQL configuration and will not be run.") + def test_issue_17(self): + """ could not connect mysql use passwod """ + conn = self.connections[0] + host = self.databases[0]["host"] + db = self.databases[0]["db"] + c = conn.cursor() + # grant access to a table to a user with a password + try: + c.execute("create table issue17 (x varchar(32) primary key)") + c.execute("insert into issue17 (x) values ('hello, world!')") + c.execute("grant all privileges on %s.issue17 to 'issue17user'@'%%' identified by '1234'" % db) + conn.commit() + + conn2 = pymysql.connect(host=host, user="issue17user", passwd="1234", db=db) + c2 = conn2.cursor() + c2.execute("select x from issue17") + self.assertEqual("hello, world!", c2.fetchone()[0]) + finally: + c.execute("drop table issue17") + +def _uni(s, e): + # hack for py3 + if sys.version_info[0] > 2: + return unicode(bytes(s, sys.getdefaultencoding()), e) + else: + return unicode(s, e) + +class TestNewIssues(base.PyMySQLTestCase): + def test_issue_34(self): + try: + pymysql.connect(host="localhost", port=1237, user="root") + self.fail() + except pymysql.OperationalError, e: + self.assertEqual(2003, e.args[0]) + except: + self.fail() + + def test_issue_33(self): + conn = pymysql.connect(host="localhost", user="root", db=self.databases[0]["db"], charset="utf8") + c = conn.cursor() + try: + c.execute(_uni("create table hei\xc3\x9fe (name varchar(32))", "utf8")) + c.execute(_uni("insert into hei\xc3\x9fe (name) values ('Pi\xc3\xb1ata')", "utf8")) + c.execute(_uni("select name from hei\xc3\x9fe", "utf8")) + self.assertEqual(_uni("Pi\xc3\xb1ata","utf8"), c.fetchone()[0]) + finally: + c.execute(_uni("drop table hei\xc3\x9fe", "utf8")) + + @unittest.skip("This test requires manual intervention") + def test_issue_35(self): + conn = self.connections[0] + c = conn.cursor() + print "sudo killall -9 mysqld within the next 10 seconds" + try: + c.execute("select sleep(10)") + self.fail() + except pymysql.OperationalError, e: + self.assertEqual(2013, e.args[0]) + + def test_issue_36(self): + conn = self.connections[0] + c = conn.cursor() + # kill connections[0] + c.execute("show processlist") + kill_id = None + for id,user,host,db,command,time,state,info in c.fetchall(): + if info == "show processlist": + kill_id = id + break + # now nuke the connection + conn.kill(kill_id) + # make sure this connection has broken + try: + c.execute("show tables") + self.fail() + except: + pass + # check the process list from the other connection + try: + c = self.connections[1].cursor() + c.execute("show processlist") + ids = [row[0] for row in c.fetchall()] + self.assertFalse(kill_id in ids) + finally: + del self.connections[0] + + def test_issue_37(self): + conn = self.connections[0] + c = conn.cursor() + self.assertEqual(1, c.execute("SELECT @foo")) + self.assertEqual((None,), c.fetchone()) + self.assertEqual(0, c.execute("SET @foo = 'bar'")) + c.execute("set @foo = 'bar'") + + def test_issue_38(self): + conn = self.connections[0] + c = conn.cursor() + datum = "a" * 1024 * 1023 # reduced size for most default mysql installs + + try: + c.execute("create table issue38 (id integer, data mediumblob)") + c.execute("insert into issue38 values (1, %s)", (datum,)) + finally: + c.execute("drop table issue38") + + def disabled_test_issue_54(self): + conn = self.connections[0] + c = conn.cursor() + big_sql = "select * from issue54 where " + big_sql += " and ".join("%d=%d" % (i,i) for i in xrange(0, 100000)) + + try: + c.execute("create table issue54 (id integer primary key)") + c.execute("insert into issue54 (id) values (7)") + c.execute(big_sql) + self.assertEqual(7, c.fetchone()[0]) + finally: + c.execute("drop table issue54") + +class TestGitHubIssues(base.PyMySQLTestCase): + def test_issue_66(self): + conn = self.connections[0] + c = conn.cursor() + self.assertEqual(0, conn.insert_id()) + try: + c.execute("create table issue66 (id integer primary key auto_increment, x integer)") + c.execute("insert into issue66 (x) values (1)") + c.execute("insert into issue66 (x) values (1)") + self.assertEqual(2, conn.insert_id()) + finally: + c.execute("drop table issue66") + +__all__ = ["TestOldIssues", "TestNewIssues", "TestGitHubIssues"] + +if __name__ == "__main__": + import unittest + unittest.main() diff --git a/lib/pymysql/tests/thirdparty/__init__.py b/lib/pymysql/tests/thirdparty/__init__.py new file mode 100644 index 0000000..bfcc075 --- /dev/null +++ b/lib/pymysql/tests/thirdparty/__init__.py @@ -0,0 +1,5 @@ +from test_MySQLdb import * + +if __name__ == "__main__": + import unittest + unittest.main() diff --git a/lib/pymysql/tests/thirdparty/test_MySQLdb/__init__.py b/lib/pymysql/tests/thirdparty/test_MySQLdb/__init__.py new file mode 100644 index 0000000..b64f273 --- /dev/null +++ b/lib/pymysql/tests/thirdparty/test_MySQLdb/__init__.py @@ -0,0 +1,7 @@ +from test_MySQLdb_capabilities import test_MySQLdb as test_capabilities +from test_MySQLdb_nonstandard import * +from test_MySQLdb_dbapi20 import test_MySQLdb as test_dbapi2 + +if __name__ == "__main__": + import unittest + unittest.main() diff --git a/lib/pymysql/tests/thirdparty/test_MySQLdb/capabilities.py b/lib/pymysql/tests/thirdparty/test_MySQLdb/capabilities.py new file mode 100644 index 0000000..ddd0123 --- /dev/null +++ b/lib/pymysql/tests/thirdparty/test_MySQLdb/capabilities.py @@ -0,0 +1,292 @@ +#!/usr/bin/env python -O +""" Script to test database capabilities and the DB-API interface + for functionality and memory leaks. + + Adapted from a script by M-A Lemburg. + +""" +from time import time +import array +import unittest + + +class DatabaseTest(unittest.TestCase): + + db_module = None + connect_args = () + connect_kwargs = dict(use_unicode=True, charset="utf8") + create_table_extra = "ENGINE=INNODB CHARACTER SET UTF8" + rows = 10 + debug = False + + def setUp(self): + import gc + db = self.db_module.connect(*self.connect_args, **self.connect_kwargs) + self.connection = db + self.cursor = db.cursor() + self.BLOBText = ''.join([chr(i) for i in range(256)] * 100); + self.BLOBUText = u''.join([unichr(i) for i in range(16834)]) + self.BLOBBinary = self.db_module.Binary(''.join([chr(i) for i in range(256)] * 16)) + + leak_test = True + + def tearDown(self): + if self.leak_test: + import gc + del self.cursor + orphans = gc.collect() + self.assertFalse(orphans, "%d orphaned objects found after deleting cursor" % orphans) + + del self.connection + orphans = gc.collect() + self.assertFalse(orphans, "%d orphaned objects found after deleting connection" % orphans) + + def table_exists(self, name): + try: + self.cursor.execute('select * from %s where 1=0' % name) + except: + return False + else: + return True + + def quote_identifier(self, ident): + return '"%s"' % ident + + def new_table_name(self): + i = id(self.cursor) + while True: + name = self.quote_identifier('tb%08x' % i) + if not self.table_exists(name): + return name + i = i + 1 + + def create_table(self, columndefs): + + """ Create a table using a list of column definitions given in + columndefs. + + generator must be a function taking arguments (row_number, + col_number) returning a suitable data object for insertion + into the table. + + """ + self.table = self.new_table_name() + self.cursor.execute('CREATE TABLE %s (%s) %s' % + (self.table, + ',\n'.join(columndefs), + self.create_table_extra)) + + def check_data_integrity(self, columndefs, generator): + # insert + self.create_table(columndefs) + insert_statement = ('INSERT INTO %s VALUES (%s)' % + (self.table, + ','.join(['%s'] * len(columndefs)))) + data = [ [ generator(i,j) for j in range(len(columndefs)) ] + for i in range(self.rows) ] + if self.debug: + print data + self.cursor.executemany(insert_statement, data) + self.connection.commit() + # verify + self.cursor.execute('select * from %s' % self.table) + l = self.cursor.fetchall() + if self.debug: + print l + self.assertEquals(len(l), self.rows) + try: + for i in range(self.rows): + for j in range(len(columndefs)): + self.assertEquals(l[i][j], generator(i,j)) + finally: + if not self.debug: + self.cursor.execute('drop table %s' % (self.table)) + + def test_transactions(self): + columndefs = ( 'col1 INT', 'col2 VARCHAR(255)') + def generator(row, col): + if col == 0: return row + else: return ('%i' % (row%10))*255 + self.create_table(columndefs) + insert_statement = ('INSERT INTO %s VALUES (%s)' % + (self.table, + ','.join(['%s'] * len(columndefs)))) + data = [ [ generator(i,j) for j in range(len(columndefs)) ] + for i in range(self.rows) ] + self.cursor.executemany(insert_statement, data) + # verify + self.connection.commit() + self.cursor.execute('select * from %s' % self.table) + l = self.cursor.fetchall() + self.assertEquals(len(l), self.rows) + for i in range(self.rows): + for j in range(len(columndefs)): + self.assertEquals(l[i][j], generator(i,j)) + delete_statement = 'delete from %s where col1=%%s' % self.table + self.cursor.execute(delete_statement, (0,)) + self.cursor.execute('select col1 from %s where col1=%s' % \ + (self.table, 0)) + l = self.cursor.fetchall() + self.assertFalse(l, "DELETE didn't work") + self.connection.rollback() + self.cursor.execute('select col1 from %s where col1=%s' % \ + (self.table, 0)) + l = self.cursor.fetchall() + self.assertTrue(len(l) == 1, "ROLLBACK didn't work") + self.cursor.execute('drop table %s' % (self.table)) + + def test_truncation(self): + columndefs = ( 'col1 INT', 'col2 VARCHAR(255)') + def generator(row, col): + if col == 0: return row + else: return ('%i' % (row%10))*((255-self.rows/2)+row) + self.create_table(columndefs) + insert_statement = ('INSERT INTO %s VALUES (%s)' % + (self.table, + ','.join(['%s'] * len(columndefs)))) + + try: + self.cursor.execute(insert_statement, (0, '0'*256)) + except Warning: + if self.debug: print self.cursor.messages + except self.connection.DataError: + pass + else: + self.fail("Over-long column did not generate warnings/exception with single insert") + + self.connection.rollback() + + try: + for i in range(self.rows): + data = [] + for j in range(len(columndefs)): + data.append(generator(i,j)) + self.cursor.execute(insert_statement,tuple(data)) + except Warning: + if self.debug: print self.cursor.messages + except self.connection.DataError: + pass + else: + self.fail("Over-long columns did not generate warnings/exception with execute()") + + self.connection.rollback() + + try: + data = [ [ generator(i,j) for j in range(len(columndefs)) ] + for i in range(self.rows) ] + self.cursor.executemany(insert_statement, data) + except Warning: + if self.debug: print self.cursor.messages + except self.connection.DataError: + pass + else: + self.fail("Over-long columns did not generate warnings/exception with executemany()") + + self.connection.rollback() + self.cursor.execute('drop table %s' % (self.table)) + + def test_CHAR(self): + # Character data + def generator(row,col): + return ('%i' % ((row+col) % 10)) * 255 + self.check_data_integrity( + ('col1 char(255)','col2 char(255)'), + generator) + + def test_INT(self): + # Number data + def generator(row,col): + return row*row + self.check_data_integrity( + ('col1 INT',), + generator) + + def test_DECIMAL(self): + # DECIMAL + def generator(row,col): + from decimal import Decimal + return Decimal("%d.%02d" % (row, col)) + self.check_data_integrity( + ('col1 DECIMAL(5,2)',), + generator) + + def test_DATE(self): + ticks = time() + def generator(row,col): + return self.db_module.DateFromTicks(ticks+row*86400-col*1313) + self.check_data_integrity( + ('col1 DATE',), + generator) + + def test_TIME(self): + ticks = time() + def generator(row,col): + return self.db_module.TimeFromTicks(ticks+row*86400-col*1313) + self.check_data_integrity( + ('col1 TIME',), + generator) + + def test_DATETIME(self): + ticks = time() + def generator(row,col): + return self.db_module.TimestampFromTicks(ticks+row*86400-col*1313) + self.check_data_integrity( + ('col1 DATETIME',), + generator) + + def test_TIMESTAMP(self): + ticks = time() + def generator(row,col): + return self.db_module.TimestampFromTicks(ticks+row*86400-col*1313) + self.check_data_integrity( + ('col1 TIMESTAMP',), + generator) + + def test_fractional_TIMESTAMP(self): + ticks = time() + def generator(row,col): + return self.db_module.TimestampFromTicks(ticks+row*86400-col*1313+row*0.7*col/3.0) + self.check_data_integrity( + ('col1 TIMESTAMP',), + generator) + + def test_LONG(self): + def generator(row,col): + if col == 0: + return row + else: + return self.BLOBUText # 'BLOB Text ' * 1024 + self.check_data_integrity( + ('col1 INT', 'col2 LONG'), + generator) + + def test_TEXT(self): + def generator(row,col): + if col == 0: + return row + else: + return self.BLOBUText[:5192] # 'BLOB Text ' * 1024 + self.check_data_integrity( + ('col1 INT', 'col2 TEXT'), + generator) + + def test_LONG_BYTE(self): + def generator(row,col): + if col == 0: + return row + else: + return self.BLOBBinary # 'BLOB\000Binary ' * 1024 + self.check_data_integrity( + ('col1 INT','col2 LONG BYTE'), + generator) + + def test_BLOB(self): + def generator(row,col): + if col == 0: + return row + else: + return self.BLOBBinary # 'BLOB\000Binary ' * 1024 + self.check_data_integrity( + ('col1 INT','col2 BLOB'), + generator) + diff --git a/lib/pymysql/tests/thirdparty/test_MySQLdb/dbapi20.py b/lib/pymysql/tests/thirdparty/test_MySQLdb/dbapi20.py new file mode 100644 index 0000000..a419e34 --- /dev/null +++ b/lib/pymysql/tests/thirdparty/test_MySQLdb/dbapi20.py @@ -0,0 +1,853 @@ +#!/usr/bin/env python +''' Python DB API 2.0 driver compliance unit test suite. + + This software is Public Domain and may be used without restrictions. + + "Now we have booze and barflies entering the discussion, plus rumours of + DBAs on drugs... and I won't tell you what flashes through my mind each + time I read the subject line with 'Anal Compliance' in it. All around + this is turning out to be a thoroughly unwholesome unit test." + + -- Ian Bicking +''' + +__rcs_id__ = '$Id$' +__version__ = '$Revision$'[11:-2] +__author__ = 'Stuart Bishop ' + +import unittest +import time + +# $Log$ +# Revision 1.1.2.1 2006/02/25 03:44:32 adustman +# Generic DB-API unit test module +# +# Revision 1.10 2003/10/09 03:14:14 zenzen +# Add test for DB API 2.0 optional extension, where database exceptions +# are exposed as attributes on the Connection object. +# +# Revision 1.9 2003/08/13 01:16:36 zenzen +# Minor tweak from Stefan Fleiter +# +# Revision 1.8 2003/04/10 00:13:25 zenzen +# Changes, as per suggestions by M.-A. Lemburg +# - Add a table prefix, to ensure namespace collisions can always be avoided +# +# Revision 1.7 2003/02/26 23:33:37 zenzen +# Break out DDL into helper functions, as per request by David Rushby +# +# Revision 1.6 2003/02/21 03:04:33 zenzen +# Stuff from Henrik Ekelund: +# added test_None +# added test_nextset & hooks +# +# Revision 1.5 2003/02/17 22:08:43 zenzen +# Implement suggestions and code from Henrik Eklund - test that cursor.arraysize +# defaults to 1 & generic cursor.callproc test added +# +# Revision 1.4 2003/02/15 00:16:33 zenzen +# Changes, as per suggestions and bug reports by M.-A. Lemburg, +# Matthew T. Kromer, Federico Di Gregorio and Daniel Dittmar +# - Class renamed +# - Now a subclass of TestCase, to avoid requiring the driver stub +# to use multiple inheritance +# - Reversed the polarity of buggy test in test_description +# - Test exception heirarchy correctly +# - self.populate is now self._populate(), so if a driver stub +# overrides self.ddl1 this change propogates +# - VARCHAR columns now have a width, which will hopefully make the +# DDL even more portible (this will be reversed if it causes more problems) +# - cursor.rowcount being checked after various execute and fetchXXX methods +# - Check for fetchall and fetchmany returning empty lists after results +# are exhausted (already checking for empty lists if select retrieved +# nothing +# - Fix bugs in test_setoutputsize_basic and test_setinputsizes +# + +class DatabaseAPI20Test(unittest.TestCase): + ''' Test a database self.driver for DB API 2.0 compatibility. + This implementation tests Gadfly, but the TestCase + is structured so that other self.drivers can subclass this + test case to ensure compiliance with the DB-API. It is + expected that this TestCase may be expanded in the future + if ambiguities or edge conditions are discovered. + + The 'Optional Extensions' are not yet being tested. + + self.drivers should subclass this test, overriding setUp, tearDown, + self.driver, connect_args and connect_kw_args. Class specification + should be as follows: + + import dbapi20 + class mytest(dbapi20.DatabaseAPI20Test): + [...] + + Don't 'import DatabaseAPI20Test from dbapi20', or you will + confuse the unit tester - just 'import dbapi20'. + ''' + + # The self.driver module. This should be the module where the 'connect' + # method is to be found + driver = None + connect_args = () # List of arguments to pass to connect + connect_kw_args = {} # Keyword arguments for connect + table_prefix = 'dbapi20test_' # If you need to specify a prefix for tables + + ddl1 = 'create table %sbooze (name varchar(20))' % table_prefix + ddl2 = 'create table %sbarflys (name varchar(20))' % table_prefix + xddl1 = 'drop table %sbooze' % table_prefix + xddl2 = 'drop table %sbarflys' % table_prefix + + lowerfunc = 'lower' # Name of stored procedure to convert string->lowercase + + # Some drivers may need to override these helpers, for example adding + # a 'commit' after the execute. + def executeDDL1(self,cursor): + cursor.execute(self.ddl1) + + def executeDDL2(self,cursor): + cursor.execute(self.ddl2) + + def setUp(self): + ''' self.drivers should override this method to perform required setup + if any is necessary, such as creating the database. + ''' + pass + + def tearDown(self): + ''' self.drivers should override this method to perform required cleanup + if any is necessary, such as deleting the test database. + The default drops the tables that may be created. + ''' + con = self._connect() + try: + cur = con.cursor() + for ddl in (self.xddl1,self.xddl2): + try: + cur.execute(ddl) + con.commit() + except self.driver.Error: + # Assume table didn't exist. Other tests will check if + # execute is busted. + pass + finally: + con.close() + + def _connect(self): + try: + return self.driver.connect( + *self.connect_args,**self.connect_kw_args + ) + except AttributeError: + self.fail("No connect method found in self.driver module") + + def test_connect(self): + con = self._connect() + con.close() + + def test_apilevel(self): + try: + # Must exist + apilevel = self.driver.apilevel + # Must equal 2.0 + self.assertEqual(apilevel,'2.0') + except AttributeError: + self.fail("Driver doesn't define apilevel") + + def test_threadsafety(self): + try: + # Must exist + threadsafety = self.driver.threadsafety + # Must be a valid value + self.assertTrue(threadsafety in (0,1,2,3)) + except AttributeError: + self.fail("Driver doesn't define threadsafety") + + def test_paramstyle(self): + try: + # Must exist + paramstyle = self.driver.paramstyle + # Must be a valid value + self.assertTrue(paramstyle in ( + 'qmark','numeric','named','format','pyformat' + )) + except AttributeError: + self.fail("Driver doesn't define paramstyle") + + def test_Exceptions(self): + # Make sure required exceptions exist, and are in the + # defined heirarchy. + self.assertTrue(issubclass(self.driver.Warning,StandardError)) + self.assertTrue(issubclass(self.driver.Error,StandardError)) + self.assertTrue( + issubclass(self.driver.InterfaceError,self.driver.Error) + ) + self.assertTrue( + issubclass(self.driver.DatabaseError,self.driver.Error) + ) + self.assertTrue( + issubclass(self.driver.OperationalError,self.driver.Error) + ) + self.assertTrue( + issubclass(self.driver.IntegrityError,self.driver.Error) + ) + self.assertTrue( + issubclass(self.driver.InternalError,self.driver.Error) + ) + self.assertTrue( + issubclass(self.driver.ProgrammingError,self.driver.Error) + ) + self.assertTrue( + issubclass(self.driver.NotSupportedError,self.driver.Error) + ) + + def test_ExceptionsAsConnectionAttributes(self): + # OPTIONAL EXTENSION + # Test for the optional DB API 2.0 extension, where the exceptions + # are exposed as attributes on the Connection object + # I figure this optional extension will be implemented by any + # driver author who is using this test suite, so it is enabled + # by default. + con = self._connect() + drv = self.driver + self.assertTrue(con.Warning is drv.Warning) + self.assertTrue(con.Error is drv.Error) + self.assertTrue(con.InterfaceError is drv.InterfaceError) + self.assertTrue(con.DatabaseError is drv.DatabaseError) + self.assertTrue(con.OperationalError is drv.OperationalError) + self.assertTrue(con.IntegrityError is drv.IntegrityError) + self.assertTrue(con.InternalError is drv.InternalError) + self.assertTrue(con.ProgrammingError is drv.ProgrammingError) + self.assertTrue(con.NotSupportedError is drv.NotSupportedError) + + + def test_commit(self): + con = self._connect() + try: + # Commit must work, even if it doesn't do anything + con.commit() + finally: + con.close() + + def test_rollback(self): + con = self._connect() + # If rollback is defined, it should either work or throw + # the documented exception + if hasattr(con,'rollback'): + try: + con.rollback() + except self.driver.NotSupportedError: + pass + + def test_cursor(self): + con = self._connect() + try: + cur = con.cursor() + finally: + con.close() + + def test_cursor_isolation(self): + con = self._connect() + try: + # Make sure cursors created from the same connection have + # the documented transaction isolation level + cur1 = con.cursor() + cur2 = con.cursor() + self.executeDDL1(cur1) + cur1.execute("insert into %sbooze values ('Victoria Bitter')" % ( + self.table_prefix + )) + cur2.execute("select name from %sbooze" % self.table_prefix) + booze = cur2.fetchall() + self.assertEqual(len(booze),1) + self.assertEqual(len(booze[0]),1) + self.assertEqual(booze[0][0],'Victoria Bitter') + finally: + con.close() + + def test_description(self): + con = self._connect() + try: + cur = con.cursor() + self.executeDDL1(cur) + self.assertEqual(cur.description,None, + 'cursor.description should be none after executing a ' + 'statement that can return no rows (such as DDL)' + ) + cur.execute('select name from %sbooze' % self.table_prefix) + self.assertEqual(len(cur.description),1, + 'cursor.description describes too many columns' + ) + self.assertEqual(len(cur.description[0]),7, + 'cursor.description[x] tuples must have 7 elements' + ) + self.assertEqual(cur.description[0][0].lower(),'name', + 'cursor.description[x][0] must return column name' + ) + self.assertEqual(cur.description[0][1],self.driver.STRING, + 'cursor.description[x][1] must return column type. Got %r' + % cur.description[0][1] + ) + + # Make sure self.description gets reset + self.executeDDL2(cur) + self.assertEqual(cur.description,None, + 'cursor.description not being set to None when executing ' + 'no-result statements (eg. DDL)' + ) + finally: + con.close() + + def test_rowcount(self): + con = self._connect() + try: + cur = con.cursor() + self.executeDDL1(cur) + self.assertEqual(cur.rowcount,-1, + 'cursor.rowcount should be -1 after executing no-result ' + 'statements' + ) + cur.execute("insert into %sbooze values ('Victoria Bitter')" % ( + self.table_prefix + )) + self.assertTrue(cur.rowcount in (-1,1), + 'cursor.rowcount should == number or rows inserted, or ' + 'set to -1 after executing an insert statement' + ) + cur.execute("select name from %sbooze" % self.table_prefix) + self.assertTrue(cur.rowcount in (-1,1), + 'cursor.rowcount should == number of rows returned, or ' + 'set to -1 after executing a select statement' + ) + self.executeDDL2(cur) + self.assertEqual(cur.rowcount,-1, + 'cursor.rowcount not being reset to -1 after executing ' + 'no-result statements' + ) + finally: + con.close() + + lower_func = 'lower' + def test_callproc(self): + con = self._connect() + try: + cur = con.cursor() + if self.lower_func and hasattr(cur,'callproc'): + r = cur.callproc(self.lower_func,('FOO',)) + self.assertEqual(len(r),1) + self.assertEqual(r[0],'FOO') + r = cur.fetchall() + self.assertEqual(len(r),1,'callproc produced no result set') + self.assertEqual(len(r[0]),1, + 'callproc produced invalid result set' + ) + self.assertEqual(r[0][0],'foo', + 'callproc produced invalid results' + ) + finally: + con.close() + + def test_close(self): + con = self._connect() + try: + cur = con.cursor() + finally: + con.close() + + # cursor.execute should raise an Error if called after connection + # closed + self.assertRaises(self.driver.Error,self.executeDDL1,cur) + + # connection.commit should raise an Error if called after connection' + # closed.' + self.assertRaises(self.driver.Error,con.commit) + + # connection.close should raise an Error if called more than once + self.assertRaises(self.driver.Error,con.close) + + def test_execute(self): + con = self._connect() + try: + cur = con.cursor() + self._paraminsert(cur) + finally: + con.close() + + def _paraminsert(self,cur): + self.executeDDL1(cur) + cur.execute("insert into %sbooze values ('Victoria Bitter')" % ( + self.table_prefix + )) + self.assertTrue(cur.rowcount in (-1,1)) + + if self.driver.paramstyle == 'qmark': + cur.execute( + 'insert into %sbooze values (?)' % self.table_prefix, + ("Cooper's",) + ) + elif self.driver.paramstyle == 'numeric': + cur.execute( + 'insert into %sbooze values (:1)' % self.table_prefix, + ("Cooper's",) + ) + elif self.driver.paramstyle == 'named': + cur.execute( + 'insert into %sbooze values (:beer)' % self.table_prefix, + {'beer':"Cooper's"} + ) + elif self.driver.paramstyle == 'format': + cur.execute( + 'insert into %sbooze values (%%s)' % self.table_prefix, + ("Cooper's",) + ) + elif self.driver.paramstyle == 'pyformat': + cur.execute( + 'insert into %sbooze values (%%(beer)s)' % self.table_prefix, + {'beer':"Cooper's"} + ) + else: + self.fail('Invalid paramstyle') + self.assertTrue(cur.rowcount in (-1,1)) + + cur.execute('select name from %sbooze' % self.table_prefix) + res = cur.fetchall() + self.assertEqual(len(res),2,'cursor.fetchall returned too few rows') + beers = [res[0][0],res[1][0]] + beers.sort() + self.assertEqual(beers[0],"Cooper's", + 'cursor.fetchall retrieved incorrect data, or data inserted ' + 'incorrectly' + ) + self.assertEqual(beers[1],"Victoria Bitter", + 'cursor.fetchall retrieved incorrect data, or data inserted ' + 'incorrectly' + ) + + def test_executemany(self): + con = self._connect() + try: + cur = con.cursor() + self.executeDDL1(cur) + largs = [ ("Cooper's",) , ("Boag's",) ] + margs = [ {'beer': "Cooper's"}, {'beer': "Boag's"} ] + if self.driver.paramstyle == 'qmark': + cur.executemany( + 'insert into %sbooze values (?)' % self.table_prefix, + largs + ) + elif self.driver.paramstyle == 'numeric': + cur.executemany( + 'insert into %sbooze values (:1)' % self.table_prefix, + largs + ) + elif self.driver.paramstyle == 'named': + cur.executemany( + 'insert into %sbooze values (:beer)' % self.table_prefix, + margs + ) + elif self.driver.paramstyle == 'format': + cur.executemany( + 'insert into %sbooze values (%%s)' % self.table_prefix, + largs + ) + elif self.driver.paramstyle == 'pyformat': + cur.executemany( + 'insert into %sbooze values (%%(beer)s)' % ( + self.table_prefix + ), + margs + ) + else: + self.fail('Unknown paramstyle') + self.assertTrue(cur.rowcount in (-1,2), + 'insert using cursor.executemany set cursor.rowcount to ' + 'incorrect value %r' % cur.rowcount + ) + cur.execute('select name from %sbooze' % self.table_prefix) + res = cur.fetchall() + self.assertEqual(len(res),2, + 'cursor.fetchall retrieved incorrect number of rows' + ) + beers = [res[0][0],res[1][0]] + beers.sort() + self.assertEqual(beers[0],"Boag's",'incorrect data retrieved') + self.assertEqual(beers[1],"Cooper's",'incorrect data retrieved') + finally: + con.close() + + def test_fetchone(self): + con = self._connect() + try: + cur = con.cursor() + + # cursor.fetchone should raise an Error if called before + # executing a select-type query + self.assertRaises(self.driver.Error,cur.fetchone) + + # cursor.fetchone should raise an Error if called after + # executing a query that cannnot return rows + self.executeDDL1(cur) + self.assertRaises(self.driver.Error,cur.fetchone) + + cur.execute('select name from %sbooze' % self.table_prefix) + self.assertEqual(cur.fetchone(),None, + 'cursor.fetchone should return None if a query retrieves ' + 'no rows' + ) + self.assertTrue(cur.rowcount in (-1,0)) + + # cursor.fetchone should raise an Error if called after + # executing a query that cannnot return rows + cur.execute("insert into %sbooze values ('Victoria Bitter')" % ( + self.table_prefix + )) + self.assertRaises(self.driver.Error,cur.fetchone) + + cur.execute('select name from %sbooze' % self.table_prefix) + r = cur.fetchone() + self.assertEqual(len(r),1, + 'cursor.fetchone should have retrieved a single row' + ) + self.assertEqual(r[0],'Victoria Bitter', + 'cursor.fetchone retrieved incorrect data' + ) + self.assertEqual(cur.fetchone(),None, + 'cursor.fetchone should return None if no more rows available' + ) + self.assertTrue(cur.rowcount in (-1,1)) + finally: + con.close() + + samples = [ + 'Carlton Cold', + 'Carlton Draft', + 'Mountain Goat', + 'Redback', + 'Victoria Bitter', + 'XXXX' + ] + + def _populate(self): + ''' Return a list of sql commands to setup the DB for the fetch + tests. + ''' + populate = [ + "insert into %sbooze values ('%s')" % (self.table_prefix,s) + for s in self.samples + ] + return populate + + def test_fetchmany(self): + con = self._connect() + try: + cur = con.cursor() + + # cursor.fetchmany should raise an Error if called without + #issuing a query + self.assertRaises(self.driver.Error,cur.fetchmany,4) + + self.executeDDL1(cur) + for sql in self._populate(): + cur.execute(sql) + + cur.execute('select name from %sbooze' % self.table_prefix) + r = cur.fetchmany() + self.assertEqual(len(r),1, + 'cursor.fetchmany retrieved incorrect number of rows, ' + 'default of arraysize is one.' + ) + cur.arraysize=10 + r = cur.fetchmany(3) # Should get 3 rows + self.assertEqual(len(r),3, + 'cursor.fetchmany retrieved incorrect number of rows' + ) + r = cur.fetchmany(4) # Should get 2 more + self.assertEqual(len(r),2, + 'cursor.fetchmany retrieved incorrect number of rows' + ) + r = cur.fetchmany(4) # Should be an empty sequence + self.assertEqual(len(r),0, + 'cursor.fetchmany should return an empty sequence after ' + 'results are exhausted' + ) + self.assertTrue(cur.rowcount in (-1,6)) + + # Same as above, using cursor.arraysize + cur.arraysize=4 + cur.execute('select name from %sbooze' % self.table_prefix) + r = cur.fetchmany() # Should get 4 rows + self.assertEqual(len(r),4, + 'cursor.arraysize not being honoured by fetchmany' + ) + r = cur.fetchmany() # Should get 2 more + self.assertEqual(len(r),2) + r = cur.fetchmany() # Should be an empty sequence + self.assertEqual(len(r),0) + self.assertTrue(cur.rowcount in (-1,6)) + + cur.arraysize=6 + cur.execute('select name from %sbooze' % self.table_prefix) + rows = cur.fetchmany() # Should get all rows + self.assertTrue(cur.rowcount in (-1,6)) + self.assertEqual(len(rows),6) + self.assertEqual(len(rows),6) + rows = [r[0] for r in rows] + rows.sort() + + # Make sure we get the right data back out + for i in range(0,6): + self.assertEqual(rows[i],self.samples[i], + 'incorrect data retrieved by cursor.fetchmany' + ) + + rows = cur.fetchmany() # Should return an empty list + self.assertEqual(len(rows),0, + 'cursor.fetchmany should return an empty sequence if ' + 'called after the whole result set has been fetched' + ) + self.assertTrue(cur.rowcount in (-1,6)) + + self.executeDDL2(cur) + cur.execute('select name from %sbarflys' % self.table_prefix) + r = cur.fetchmany() # Should get empty sequence + self.assertEqual(len(r),0, + 'cursor.fetchmany should return an empty sequence if ' + 'query retrieved no rows' + ) + self.assertTrue(cur.rowcount in (-1,0)) + + finally: + con.close() + + def test_fetchall(self): + con = self._connect() + try: + cur = con.cursor() + # cursor.fetchall should raise an Error if called + # without executing a query that may return rows (such + # as a select) + self.assertRaises(self.driver.Error, cur.fetchall) + + self.executeDDL1(cur) + for sql in self._populate(): + cur.execute(sql) + + # cursor.fetchall should raise an Error if called + # after executing a a statement that cannot return rows + self.assertRaises(self.driver.Error,cur.fetchall) + + cur.execute('select name from %sbooze' % self.table_prefix) + rows = cur.fetchall() + self.assertTrue(cur.rowcount in (-1,len(self.samples))) + self.assertEqual(len(rows),len(self.samples), + 'cursor.fetchall did not retrieve all rows' + ) + rows = [r[0] for r in rows] + rows.sort() + for i in range(0,len(self.samples)): + self.assertEqual(rows[i],self.samples[i], + 'cursor.fetchall retrieved incorrect rows' + ) + rows = cur.fetchall() + self.assertEqual( + len(rows),0, + 'cursor.fetchall should return an empty list if called ' + 'after the whole result set has been fetched' + ) + self.assertTrue(cur.rowcount in (-1,len(self.samples))) + + self.executeDDL2(cur) + cur.execute('select name from %sbarflys' % self.table_prefix) + rows = cur.fetchall() + self.assertTrue(cur.rowcount in (-1,0)) + self.assertEqual(len(rows),0, + 'cursor.fetchall should return an empty list if ' + 'a select query returns no rows' + ) + + finally: + con.close() + + def test_mixedfetch(self): + con = self._connect() + try: + cur = con.cursor() + self.executeDDL1(cur) + for sql in self._populate(): + cur.execute(sql) + + cur.execute('select name from %sbooze' % self.table_prefix) + rows1 = cur.fetchone() + rows23 = cur.fetchmany(2) + rows4 = cur.fetchone() + rows56 = cur.fetchall() + self.assertTrue(cur.rowcount in (-1,6)) + self.assertEqual(len(rows23),2, + 'fetchmany returned incorrect number of rows' + ) + self.assertEqual(len(rows56),2, + 'fetchall returned incorrect number of rows' + ) + + rows = [rows1[0]] + rows.extend([rows23[0][0],rows23[1][0]]) + rows.append(rows4[0]) + rows.extend([rows56[0][0],rows56[1][0]]) + rows.sort() + for i in range(0,len(self.samples)): + self.assertEqual(rows[i],self.samples[i], + 'incorrect data retrieved or inserted' + ) + finally: + con.close() + + def help_nextset_setUp(self,cur): + ''' Should create a procedure called deleteme + that returns two result sets, first the + number of rows in booze then "name from booze" + ''' + raise NotImplementedError,'Helper not implemented' + #sql=""" + # create procedure deleteme as + # begin + # select count(*) from booze + # select name from booze + # end + #""" + #cur.execute(sql) + + def help_nextset_tearDown(self,cur): + 'If cleaning up is needed after nextSetTest' + raise NotImplementedError,'Helper not implemented' + #cur.execute("drop procedure deleteme") + + def test_nextset(self): + con = self._connect() + try: + cur = con.cursor() + if not hasattr(cur,'nextset'): + return + + try: + self.executeDDL1(cur) + sql=self._populate() + for sql in self._populate(): + cur.execute(sql) + + self.help_nextset_setUp(cur) + + cur.callproc('deleteme') + numberofrows=cur.fetchone() + assert numberofrows[0]== len(self.samples) + assert cur.nextset() + names=cur.fetchall() + assert len(names) == len(self.samples) + s=cur.nextset() + assert s == None,'No more return sets, should return None' + finally: + self.help_nextset_tearDown(cur) + + finally: + con.close() + + def test_nextset(self): + raise NotImplementedError,'Drivers need to override this test' + + def test_arraysize(self): + # Not much here - rest of the tests for this are in test_fetchmany + con = self._connect() + try: + cur = con.cursor() + self.assertTrue(hasattr(cur,'arraysize'), + 'cursor.arraysize must be defined' + ) + finally: + con.close() + + def test_setinputsizes(self): + con = self._connect() + try: + cur = con.cursor() + cur.setinputsizes( (25,) ) + self._paraminsert(cur) # Make sure cursor still works + finally: + con.close() + + def test_setoutputsize_basic(self): + # Basic test is to make sure setoutputsize doesn't blow up + con = self._connect() + try: + cur = con.cursor() + cur.setoutputsize(1000) + cur.setoutputsize(2000,0) + self._paraminsert(cur) # Make sure the cursor still works + finally: + con.close() + + def test_setoutputsize(self): + # Real test for setoutputsize is driver dependant + raise NotImplementedError,'Driver need to override this test' + + def test_None(self): + con = self._connect() + try: + cur = con.cursor() + self.executeDDL1(cur) + cur.execute('insert into %sbooze values (NULL)' % self.table_prefix) + cur.execute('select name from %sbooze' % self.table_prefix) + r = cur.fetchall() + self.assertEqual(len(r),1) + self.assertEqual(len(r[0]),1) + self.assertEqual(r[0][0],None,'NULL value not returned as None') + finally: + con.close() + + def test_Date(self): + d1 = self.driver.Date(2002,12,25) + d2 = self.driver.DateFromTicks(time.mktime((2002,12,25,0,0,0,0,0,0))) + # Can we assume this? API doesn't specify, but it seems implied + # self.assertEqual(str(d1),str(d2)) + + def test_Time(self): + t1 = self.driver.Time(13,45,30) + t2 = self.driver.TimeFromTicks(time.mktime((2001,1,1,13,45,30,0,0,0))) + # Can we assume this? API doesn't specify, but it seems implied + # self.assertEqual(str(t1),str(t2)) + + def test_Timestamp(self): + t1 = self.driver.Timestamp(2002,12,25,13,45,30) + t2 = self.driver.TimestampFromTicks( + time.mktime((2002,12,25,13,45,30,0,0,0)) + ) + # Can we assume this? API doesn't specify, but it seems implied + # self.assertEqual(str(t1),str(t2)) + + def test_Binary(self): + b = self.driver.Binary('Something') + b = self.driver.Binary('') + + def test_STRING(self): + self.assertTrue(hasattr(self.driver,'STRING'), + 'module.STRING must be defined' + ) + + def test_BINARY(self): + self.assertTrue(hasattr(self.driver,'BINARY'), + 'module.BINARY must be defined.' + ) + + def test_NUMBER(self): + self.assertTrue(hasattr(self.driver,'NUMBER'), + 'module.NUMBER must be defined.' + ) + + def test_DATETIME(self): + self.assertTrue(hasattr(self.driver,'DATETIME'), + 'module.DATETIME must be defined.' + ) + + def test_ROWID(self): + self.assertTrue(hasattr(self.driver,'ROWID'), + 'module.ROWID must be defined.' + ) + diff --git a/lib/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_capabilities.py b/lib/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_capabilities.py new file mode 100644 index 0000000..e0bc934 --- /dev/null +++ b/lib/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_capabilities.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python +import capabilities +import unittest +import pymysql +from pymysql.tests import base +import warnings + +warnings.filterwarnings('error') + +class test_MySQLdb(capabilities.DatabaseTest): + + db_module = pymysql + connect_args = () + connect_kwargs = base.PyMySQLTestCase.databases[0].copy() + connect_kwargs.update(dict(read_default_file='~/.my.cnf', + use_unicode=True, + charset='utf8', sql_mode="ANSI,STRICT_TRANS_TABLES,TRADITIONAL")) + + create_table_extra = "ENGINE=INNODB CHARACTER SET UTF8" + leak_test = False + + def quote_identifier(self, ident): + return "`%s`" % ident + + def test_TIME(self): + from datetime import timedelta + def generator(row,col): + return timedelta(0, row*8000) + self.check_data_integrity( + ('col1 TIME',), + generator) + + def test_TINYINT(self): + # Number data + def generator(row,col): + v = (row*row) % 256 + if v > 127: + v = v-256 + return v + self.check_data_integrity( + ('col1 TINYINT',), + generator) + + def test_stored_procedures(self): + db = self.connection + c = self.cursor + try: + self.create_table(('pos INT', 'tree CHAR(20)')) + c.executemany("INSERT INTO %s (pos,tree) VALUES (%%s,%%s)" % self.table, + list(enumerate('ash birch cedar larch pine'.split()))) + db.commit() + + c.execute(""" + CREATE PROCEDURE test_sp(IN t VARCHAR(255)) + BEGIN + SELECT pos FROM %s WHERE tree = t; + END + """ % self.table) + db.commit() + + c.callproc('test_sp', ('larch',)) + rows = c.fetchall() + self.assertEquals(len(rows), 1) + self.assertEquals(rows[0][0], 3) + c.nextset() + finally: + c.execute("DROP PROCEDURE IF EXISTS test_sp") + c.execute('drop table %s' % (self.table)) + + def test_small_CHAR(self): + # Character data + def generator(row,col): + i = ((row+1)*(col+1)+62)%256 + if i == 62: return '' + if i == 63: return None + return chr(i) + self.check_data_integrity( + ('col1 char(1)','col2 char(1)'), + generator) + + def test_bug_2671682(self): + from pymysql.constants import ER + try: + self.cursor.execute("describe some_non_existent_table"); + except self.connection.ProgrammingError, msg: + self.assertTrue(msg.args[0] == ER.NO_SUCH_TABLE) + + def test_insert_values(self): + from pymysql.cursors import insert_values + query = """INSERT FOO (a, b, c) VALUES (a, b, c)""" + matched = insert_values.search(query) + self.assertTrue(matched) + values = matched.group(1) + self.assertTrue(values == "(a, b, c)") + + def test_ping(self): + self.connection.ping() + + def test_literal_int(self): + self.assertTrue("2" == self.connection.literal(2)) + + def test_literal_float(self): + self.assertTrue("3.1415" == self.connection.literal(3.1415)) + + def test_literal_string(self): + self.assertTrue("'foo'" == self.connection.literal("foo")) + + +if __name__ == '__main__': + if test_MySQLdb.leak_test: + import gc + gc.enable() + gc.set_debug(gc.DEBUG_LEAK) + unittest.main() + diff --git a/lib/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py b/lib/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py new file mode 100644 index 0000000..59626e3 --- /dev/null +++ b/lib/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py @@ -0,0 +1,210 @@ +#!/usr/bin/env python +import dbapi20 +import unittest +import pymysql +from pymysql.tests import base + +# compatibility: +if not hasattr(unittest, "expectedFailure"): + unittest.expectedFailure = lambda f: f + +class test_MySQLdb(dbapi20.DatabaseAPI20Test): + driver = pymysql + connect_args = () + connect_kw_args = base.PyMySQLTestCase.databases[0].copy() + connect_kw_args.update(dict(read_default_file='~/.my.cnf', + charset='utf8', + sql_mode="ANSI,STRICT_TRANS_TABLES,TRADITIONAL")) + + def test_setoutputsize(self): pass + def test_setoutputsize_basic(self): pass + def test_nextset(self): pass + + """The tests on fetchone and fetchall and rowcount bogusly + test for an exception if the statement cannot return a + result set. MySQL always returns a result set; it's just that + some things return empty result sets.""" + + def test_fetchall(self): + con = self._connect() + try: + cur = con.cursor() + # cursor.fetchall should raise an Error if called + # without executing a query that may return rows (such + # as a select) + self.assertRaises(self.driver.Error, cur.fetchall) + + self.executeDDL1(cur) + for sql in self._populate(): + cur.execute(sql) + + # cursor.fetchall should raise an Error if called + # after executing a a statement that cannot return rows +## self.assertRaises(self.driver.Error,cur.fetchall) + + cur.execute('select name from %sbooze' % self.table_prefix) + rows = cur.fetchall() + self.assertTrue(cur.rowcount in (-1,len(self.samples))) + self.assertEqual(len(rows),len(self.samples), + 'cursor.fetchall did not retrieve all rows' + ) + rows = [r[0] for r in rows] + rows.sort() + for i in range(0,len(self.samples)): + self.assertEqual(rows[i],self.samples[i], + 'cursor.fetchall retrieved incorrect rows' + ) + rows = cur.fetchall() + self.assertEqual( + len(rows),0, + 'cursor.fetchall should return an empty list if called ' + 'after the whole result set has been fetched' + ) + self.assertTrue(cur.rowcount in (-1,len(self.samples))) + + self.executeDDL2(cur) + cur.execute('select name from %sbarflys' % self.table_prefix) + rows = cur.fetchall() + self.assertTrue(cur.rowcount in (-1,0)) + self.assertEqual(len(rows),0, + 'cursor.fetchall should return an empty list if ' + 'a select query returns no rows' + ) + + finally: + con.close() + + def test_fetchone(self): + con = self._connect() + try: + cur = con.cursor() + + # cursor.fetchone should raise an Error if called before + # executing a select-type query + self.assertRaises(self.driver.Error,cur.fetchone) + + # cursor.fetchone should raise an Error if called after + # executing a query that cannnot return rows + self.executeDDL1(cur) +## self.assertRaises(self.driver.Error,cur.fetchone) + + cur.execute('select name from %sbooze' % self.table_prefix) + self.assertEqual(cur.fetchone(),None, + 'cursor.fetchone should return None if a query retrieves ' + 'no rows' + ) + self.assertTrue(cur.rowcount in (-1,0)) + + # cursor.fetchone should raise an Error if called after + # executing a query that cannnot return rows + cur.execute("insert into %sbooze values ('Victoria Bitter')" % ( + self.table_prefix + )) +## self.assertRaises(self.driver.Error,cur.fetchone) + + cur.execute('select name from %sbooze' % self.table_prefix) + r = cur.fetchone() + self.assertEqual(len(r),1, + 'cursor.fetchone should have retrieved a single row' + ) + self.assertEqual(r[0],'Victoria Bitter', + 'cursor.fetchone retrieved incorrect data' + ) +## self.assertEqual(cur.fetchone(),None, +## 'cursor.fetchone should return None if no more rows available' +## ) + self.assertTrue(cur.rowcount in (-1,1)) + finally: + con.close() + + # Same complaint as for fetchall and fetchone + def test_rowcount(self): + con = self._connect() + try: + cur = con.cursor() + self.executeDDL1(cur) +## self.assertEqual(cur.rowcount,-1, +## 'cursor.rowcount should be -1 after executing no-result ' +## 'statements' +## ) + cur.execute("insert into %sbooze values ('Victoria Bitter')" % ( + self.table_prefix + )) +## self.assertTrue(cur.rowcount in (-1,1), +## 'cursor.rowcount should == number or rows inserted, or ' +## 'set to -1 after executing an insert statement' +## ) + cur.execute("select name from %sbooze" % self.table_prefix) + self.assertTrue(cur.rowcount in (-1,1), + 'cursor.rowcount should == number of rows returned, or ' + 'set to -1 after executing a select statement' + ) + self.executeDDL2(cur) +## self.assertEqual(cur.rowcount,-1, +## 'cursor.rowcount not being reset to -1 after executing ' +## 'no-result statements' +## ) + finally: + con.close() + + def test_callproc(self): + pass # performed in test_MySQL_capabilities + + def help_nextset_setUp(self,cur): + ''' Should create a procedure called deleteme + that returns two result sets, first the + number of rows in booze then "name from booze" + ''' + sql=""" + create procedure deleteme() + begin + select count(*) from %(tp)sbooze; + select name from %(tp)sbooze; + end + """ % dict(tp=self.table_prefix) + cur.execute(sql) + + def help_nextset_tearDown(self,cur): + 'If cleaning up is needed after nextSetTest' + cur.execute("drop procedure deleteme") + + @unittest.expectedFailure + def test_nextset(self): + from warnings import warn + con = self._connect() + try: + cur = con.cursor() + if not hasattr(cur,'nextset'): + return + + try: + self.executeDDL1(cur) + sql=self._populate() + for sql in self._populate(): + cur.execute(sql) + + self.help_nextset_setUp(cur) + + cur.callproc('deleteme') + numberofrows=cur.fetchone() + assert numberofrows[0]== len(self.samples) + assert cur.nextset() + names=cur.fetchall() + assert len(names) == len(self.samples) + s=cur.nextset() + if s: + empty = cur.fetchall() + self.assertEquals(len(empty), 0, + "non-empty result set after other result sets") + #warn("Incompatibility: MySQL returns an empty result set for the CALL itself", + # Warning) + #assert s == None,'No more return sets, should return None' + finally: + self.help_nextset_tearDown(cur) + + finally: + con.close() + + +if __name__ == '__main__': + unittest.main() diff --git a/lib/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_nonstandard.py b/lib/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_nonstandard.py new file mode 100644 index 0000000..f49369c --- /dev/null +++ b/lib/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_nonstandard.py @@ -0,0 +1,90 @@ +import unittest + +import pymysql +_mysql = pymysql +from pymysql.constants import FIELD_TYPE +from pymysql.tests import base + + +class TestDBAPISet(unittest.TestCase): + def test_set_equality(self): + self.assertTrue(pymysql.STRING == pymysql.STRING) + + def test_set_inequality(self): + self.assertTrue(pymysql.STRING != pymysql.NUMBER) + + def test_set_equality_membership(self): + self.assertTrue(FIELD_TYPE.VAR_STRING == pymysql.STRING) + + def test_set_inequality_membership(self): + self.assertTrue(FIELD_TYPE.DATE != pymysql.STRING) + + +class CoreModule(unittest.TestCase): + """Core _mysql module features.""" + + def test_NULL(self): + """Should have a NULL constant.""" + self.assertEqual(_mysql.NULL, 'NULL') + + def test_version(self): + """Version information sanity.""" + self.assertTrue(isinstance(_mysql.__version__, str)) + + self.assertTrue(isinstance(_mysql.version_info, tuple)) + self.assertEqual(len(_mysql.version_info), 5) + + def test_client_info(self): + self.assertTrue(isinstance(_mysql.get_client_info(), str)) + + def test_thread_safe(self): + self.assertTrue(isinstance(_mysql.thread_safe(), int)) + + +class CoreAPI(unittest.TestCase): + """Test _mysql interaction internals.""" + + def setUp(self): + kwargs = base.PyMySQLTestCase.databases[0].copy() + kwargs["read_default_file"] = "~/.my.cnf" + self.conn = _mysql.connect(**kwargs) + + def tearDown(self): + self.conn.close() + + def test_thread_id(self): + tid = self.conn.thread_id() + self.assertTrue(isinstance(tid, int), + "thread_id didn't return an int.") + + self.assertRaises(TypeError, self.conn.thread_id, ('evil',), + "thread_id shouldn't accept arguments.") + + def test_affected_rows(self): + self.assertEquals(self.conn.affected_rows(), 0, + "Should return 0 before we do anything.") + + + #def test_debug(self): + ## FIXME Only actually tests if you lack SUPER + #self.assertRaises(pymysql.OperationalError, + #self.conn.dump_debug_info) + + def test_charset_name(self): + self.assertTrue(isinstance(self.conn.character_set_name(), str), + "Should return a string.") + + def test_host_info(self): + self.assertTrue(isinstance(self.conn.get_host_info(), str), + "Should return a string.") + + def test_proto_info(self): + self.assertTrue(isinstance(self.conn.get_proto_info(), int), + "Should return an int.") + + def test_server_info(self): + self.assertTrue(isinstance(self.conn.get_server_info(), basestring), + "Should return an str.") + +if __name__ == "__main__": + unittest.main() diff --git a/lib/pymysql/times.py b/lib/pymysql/times.py new file mode 100644 index 0000000..c47db09 --- /dev/null +++ b/lib/pymysql/times.py @@ -0,0 +1,16 @@ +from time import localtime +from datetime import date, datetime, time, timedelta + +Date = date +Time = time +TimeDelta = timedelta +Timestamp = datetime + +def DateFromTicks(ticks): + return date(*localtime(ticks)[:3]) + +def TimeFromTicks(ticks): + return time(*localtime(ticks)[3:6]) + +def TimestampFromTicks(ticks): + return datetime(*localtime(ticks)[:6]) diff --git a/lib/pymysql/times.pyc b/lib/pymysql/times.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3a057f6e080605e6456e8e34054f4c7ec9a35be0 GIT binary patch literal 920 zcmb`FK}*9x5QS%xw6;~Lh~QN{1qAa4L*joYuaw zCQTTk(^GH!;9FoRM7bxtL7`3UrzMlnV%QPPZNPclN*+a?72Dc+6%=N_Cl&Vvne(k2 zCUcM;l&{KbmxdUf+l9+6oSC`o(w14-Xp`MO_^ak7v-%p+KDfI&BaPd`!YcMpKz=-H z>^XC>JIBJJT2i(bNH-xCNO9)d0hX9^*s2dXCuXoC&Pn`7*mID#uq(*72+NWI_J?Eb zAldEzL9QbkA)TMv+m>|Pk)EW)&fBBOL;dh=+hO7-3G>5DVSXqkoS*h76v){|&I!#q id)?s%_3Lq9j(ywc``R3k$gRPxshy~=!Y>-e!}t@HTddRo literal 0 HcmV?d00001 diff --git a/lib/pymysql/util.py b/lib/pymysql/util.py new file mode 100644 index 0000000..cc622e5 --- /dev/null +++ b/lib/pymysql/util.py @@ -0,0 +1,19 @@ +import struct + +def byte2int(b): + if isinstance(b, int): + return b + else: + return struct.unpack("!B", b)[0] + +def int2byte(i): + return struct.pack("!B", i) + +def join_bytes(bs): + if len(bs) == 0: + return "" + else: + rv = bs[0] + for b in bs[1:]: + rv += b + return rv diff --git a/lib/pymysql/util.pyc b/lib/pymysql/util.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7fc77667973b1a9844b299140518fe6a28c2cd48 GIT binary patch literal 834 zcmbtSO-sW-5S`uBVoPhQf>02|Td-iD7cU}W1#d+XL=Z%35;1L>e(Y8(v>?=fES~kv zL=o{;Lw5G<=e##>owsWF<-K+p($}ZapQ4#2LWEyYN^}FD=@mdx*{aaq3NNk{)7yosZ9K+(H`8W;hk8nkwkOBI{U!$Q~-BSRNDwE^GK!A_Jdi zEX(=LGWj1%5Nt8i5-yg)krIZ?np>OaFA#DYmO`=*Cw92(0qBBsW1;AIm$}2^z4O~T zEi}y`M$-|N#!b4$D7T0ebi^Cn2p_o8dCfUp8fRi697Y9=bdx8a53R0~?e7hf?2d(+ y3Puu0ZNZPS+Eg1#-iegh=lAHdfqoU?C##@U9>Vcp7){gogq6xesOVC$Wd3=Ay{3{gM^BSWwT6Hp`>BoD*RAa$HTqK1LN z-2;H;`WgATsrqR}sVVx&`6;RT1(hWk`FZ-e zDcSltnMwL3`T04;dO$%|pxTtwq|$U2kWP^O42*tYgM&a8Axs6cNHUrOsNW_xKczG$ K)edYr$Z!D10y35W literal 0 HcmV?d00001 diff --git a/moodle-install.py b/moodle-install.py new file mode 100644 index 0000000..2239f74 --- /dev/null +++ b/moodle-install.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import sys +import os +import shutil +import argparse +import re + +from lib import config, tools, db, moodle +Moodle = moodle.Moodle +debug = tools.debug +DB = db.DB +C = config.Conf().get + +# Arguments +parser = argparse.ArgumentParser(description='Install a Moodle instance') +parser.add_argument('-i', '--integration', action='store_true', help='create an instance from integration') +parser.add_argument('-e', '--engine', action='store', choices=['mysqli', 'pgsql'], default=C('defaultEngine'), help='database engine to use', metavar='engine') +parser.add_argument('-s', '--suffix', action='store', help='suffix for the instance name', metavar='suffix') +parser.add_argument('-v', '--version', action='store', choices=['19', '20', '21', '22', '23', 'master'], default='master', help='version of Moodle', metavar='version') +parser.add_argument('--interactive', action='store_true', help='interactive mode') +parser.add_argument('--no-install', action='store_true', help='disable the installation', dest='noinstall') +args = parser.parse_args() + +engine = args.engine +version = args.version + +cacheStable = os.path.join(C('dirs.cache'), 'moodle.git') +cacheIntegration = os.path.join(C('dirs.cache'), 'integration.git') + +# Cloning/caching repositories if necessary +if not os.path.isdir(cacheStable): + os.chdir(C('dirs.cache')) + os.system('git clone ' + C('remotes.stable') + ' moodle.git') +if not os.path.isdir(cacheIntegration): + os.chdir(C('dirs.cache')) + os.system('git clone ' +C('remotes.integration') + ' integration.git') + +# Wording version +prefixVersion = version +versionNice = version +if version == 'master': + prefixVersion = C('wording.prefixMaster') + versionNice = C('wording.master') + +# Generating parameters +if args.integration: + name = C('wording.prefixIntegration') + prefixVersion + fullname = C('wording.integration') + ' ' + versionNice + ' ' + C('wording.%s' % engine) + repository = cacheIntegration +else: + name = C('wording.prefixStable') + prefixVersion + fullname = C('wording.stable') + ' ' + versionNice + ' ' + C('wording.%s' % engine) + repository = cacheStable + +# Append the suffix +if args.suffix: + name += C('wording.suffixSeparator') + args.suffix + fullname += ' ' + args.suffix.replace('-', ' ').replace('_', ' ').title() + +installDir = os.path.join(C('dirs.store'), name) +wwwDir = os.path.join(installDir, C('wwwDir')) +dataDir = os.path.join(installDir, C('dataDir')) +linkDir = os.path.join(C('dirs.www'), name) + +# Cloning the repository +if os.path.isdir(installDir): + debug('Installation directory exists (%s)' % installDir) + # sys.exit() + + # if args.interactive: + # pass + # else: + # if args.force: + # pass + # else: + # pass +else: + os.mkdir(installDir, 0755) + os.mkdir(dataDir, 0777) + if C('useCacheAsRemote'): + os.chdir(installDir) + os.system('git clone ' + repository + ' ' + C('wwwDir')) + else: + shutil.copytree(repository, wwwDir) + +# Checking database +dbname = re.sub(r'[^a-zA-Z0-9]', '', name).lower()[:28] +db = DB(engine, C('db.%s' % engine)) +if db.dbexists(dbname): + db.dropdb(dbname) + db.createdb(dbname) +else: + db.createdb(dbname) +db.selectdb(dbname) + +# Installing +debug('Installing %s...' % name) +os.chdir(wwwDir) +if os.path.islink(linkDir): + os.remove(linkDir) +if os.path.isfile(linkDir) or os.path.isdir(linkDir): # No elif! + debug('Could not create symbolic link') +else: + os.symlink(wwwDir, linkDir) + +# Creating, fetch, pulling branches +os.system('git fetch origin') +if version == 'master': + branch = 'origin/master' + os.system('git checkout master') +else: + branch = 'origin/MOODLE_%s_STABLE' % version + os.system('git checkout -b MOODLE_%s_STABLE %s' % (version, branch)) +os.system('git pull') +os.system('git remote add mine %s' % C('remotes.mine')) +os.system('git config --local moodle.name %s' % name) +os.system('git config --local moodle.branch %s' % branch) +os.system('git config --local moodle.version %s' % version) +os.system('git config --local moodle.engine %s' % engine) + +# Launching installation process +if not args.noinstall: + + os.chdir(wwwDir) + configFile = os.path.join(wwwDir, 'config.php') + params = (C('phpEnv'), C('host'), name, dataDir, engine, dbname, C('db.%s.user' % engine), C('db.%s.passwd' % engine), C('db.%s.host' % engine), fullname, name, C('login'), C('passwd')) + status = os.system('%s admin/cli/install.php --wwwroot="http://%s/%s/" --dataroot="%s" --dbtype="%s" --dbname="%s" --dbuser="%s" --dbpass="%s" --dbhost="%s" --fullname="%s" --shortname="%s" --adminuser="%s" --adminpass="%s" --allow-unstable --agree-license --non-interactive' % params) + if status != 0: + raise Exception('Error while running the install, please manually fix the problem.') + + os.chmod(configFile, 0666) + try: + f = open(configFile, 'a') + f.seek(0, os.SEEK_END) + f.write("\n$CFG->sessioncookiepath = '/%s/';\n" % name) + f.close() + except Exception: + debug('Could not append $CFG->sessioncookiepath to config.php') + -- 2.11.0