-
Notifications
You must be signed in to change notification settings - Fork 566
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Import from Subversion 2.0.63; reworked versioning
- Loading branch information
0 parents
commit c3f6b46
Showing
37 changed files
with
11,386 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
setup.cfg | ||
MANIFEST | ||
build | ||
dist | ||
*.pdb | ||
*.pyc | ||
*.pyo | ||
tmp | ||
web/*.cmd |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
include src\*.h | ||
include src\*.cpp | ||
include tests\* | ||
include README.txt | ||
prune setup.cfg | ||
|
||
include web\* | ||
prune web\*.cmd | ||
|
||
# For some reason, I keep getting setup.PY. Probably | ||
# because I use PATHEXT on Windows. | ||
prune setup.PY | ||
include setup.py |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
|
||
Overview | ||
======== | ||
|
||
This project is a Python database module for ODBC that implements the Python DB API 2.0 | ||
specification. | ||
|
||
homepage: http://sourceforge.net/projects/pyodbc | ||
source: http://github.com/mkleehammer/pyodbc | ||
|
||
This module requires: | ||
|
||
* Python 2.4 or greater | ||
* ODBC 3.0 or greater | ||
|
||
On Windows, the easiest way to install is to use the Windows installer program available at | ||
http://sourceforge.net/projects/pyodbc. | ||
|
||
Source can be obtained at | ||
|
||
To build from source, either check the source out of version control or download a source | ||
extract and run: | ||
|
||
python setup.py build install | ||
|
||
Module Specific Behavior | ||
======================= | ||
|
||
General | ||
------- | ||
|
||
* The pyodbc.connect function accepts a single parameter: the ODBC connection string. This | ||
string is not read or modified by pyodbc, so consult the ODBC documentation or your ODBC | ||
driver's documentation for details. The general format is: | ||
|
||
cnxn = pyodbc.connect('DSN=mydsn;UID=userid;PWD=pwd') | ||
|
||
* Connection caching in the ODBC driver manager is automatically enabled. | ||
|
||
* Autocommit is not supported. Always call cnxn.commit() since the DB API specification | ||
requires a rollback when a connection is closed that was not specifically committed. | ||
|
||
* When a connection is closed, all cursors created from the connection are closed. | ||
|
||
|
||
Data Types | ||
---------- | ||
|
||
* Dates, times, and timestamps use the Python datetime module's date, time, and datetime | ||
classes. These classes can be passed directly as parameters and will be returned when | ||
querying date/time columns. | ||
|
||
* Binary data is passed and returned in Python buffer objects. | ||
|
||
* Decimal and numeric columns are passed and returned using the Python 2.4 decimal class. | ||
|
||
|
||
Convenience Methods | ||
------------------- | ||
|
||
* Cursors are iterable and returns Row objects. | ||
|
||
cursor.execute("select a,b from tmp") | ||
for row in cursor: | ||
print row | ||
|
||
|
||
* The DB API PEP does not specify the return type for Cursor.execute, so pyodbc tries to be | ||
maximally convenient: | ||
|
||
1) If a SELECT is executed, the Cursor itself is returned to allow code like the following: | ||
|
||
for row in cursor.execute("select a,b from tmp"): | ||
print row | ||
|
||
2) If an UPDATE, INSERT, or DELETE statement is issued, the number of rows affected is | ||
returned: | ||
|
||
count = cursor.execute("delete from tmp where a in (1,2,3)") | ||
|
||
3) Otherwise (CREATE TABLE, etc.), None is returned. | ||
|
||
|
||
* An execute method has been added to the Connection class. It creates a Cursor and returns | ||
whatever Cursor.execute returns. This allows for the following: | ||
|
||
for row in cnxn.execute("select a,b from tmp"): | ||
print row | ||
|
||
or | ||
|
||
rows = cnxn.execute("select * from tmp where a in (1,2,3)").fetchall() | ||
|
||
Since each call creates a new Cursor, only use this when executing a single statement. | ||
|
||
|
||
* Both Cursor.execute and Connection.execute allow parameters to be passed as additional | ||
parameters following the query. | ||
|
||
cnxn.execute("select a,b from tmp where a=? or a=?", 1, 2) | ||
|
||
The specification is not entirely clear, but most other drivers require parameters to be | ||
passed in a sequence. To ensure compatibility, pyodbc will also accept this format: | ||
|
||
cnxn.execute("select a,b from tmp where a=? or a=?", (1, 2)) | ||
|
||
|
||
* Row objects are derived from tuple to match the API specification, but they also support | ||
accessing columns by name. | ||
|
||
for row in cnxn.execute("select A,b from tmp"): | ||
print row.a, row.b | ||
|
||
|
||
* The following are not supported or are ignored: nextset, setinputsizes, setoutputsizes. | ||
|
||
|
||
* Values in Row objects can be replaced, either by name or index. Sometimes it is convenient | ||
to "preprocess" values. | ||
|
||
row = cursor.execute("select a,b from tmp").fetchone() | ||
|
||
row.a = calc(row.a) | ||
row[1] = calc(row.b) | ||
|
||
|
||
Goals / Design | ||
============== | ||
|
||
* This module should not require any 3rd party modules other than ODBC. | ||
|
||
* Only built-in data types should be used where possible. | ||
|
||
a) Reduces the number of libraries to learn. | ||
|
||
b) Reduces the number of modules and libraries to install. | ||
|
||
c) Eventually a standard is usually introduced. For example, many previous database drivers | ||
used the mxDate classes. Now that Python 2.3 has introduced built-in date/time classes, | ||
using those modules is more complicated than using the built-ins. | ||
|
||
* It should adhere to the DB API specification, but be maximally convenient where possible. | ||
The most common usages should be optimized for convenience and speed. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
#!/usr/bin/python | ||
|
||
import sys, os, re | ||
from distutils.core import setup, Command | ||
from distutils.extension import Extension | ||
from distutils.errors import * | ||
from os.path import exists, abspath, dirname, join, isdir | ||
|
||
OFFICIAL_BUILD = 9999 | ||
|
||
def main(): | ||
|
||
version_str, version = get_version() | ||
|
||
files = [ 'pyodbcmodule.cpp', 'cursor.cpp', 'row.cpp', 'connection.cpp', 'buffer.cpp', 'params.cpp', 'errors.cpp', 'getdata.cpp' ] | ||
files = [ join('src', f) for f in files ] | ||
libraries = [] | ||
|
||
extra_compile_args = None | ||
extra_link_args = None | ||
|
||
if os.name == 'nt': | ||
# Windows native | ||
files.append(join('src', 'pyodbc.rc')) | ||
libraries.append('odbc32') | ||
extra_compile_args = [ '/W4' ] | ||
|
||
# Add debugging symbols | ||
extra_compile_args = [ '/W4', '/Zi', '/Od' ] | ||
extra_link_args = [ '/DEBUG' ] | ||
|
||
elif os.environ.get("OS", '').lower().startswith('windows'): | ||
# Windows Cygwin (posix on windows) | ||
# OS name not windows, but still on Windows | ||
libraries.append('odbc32') | ||
|
||
elif sys.platform == 'darwin': | ||
# OS/X now ships with iODBC. | ||
libraries.append('iodbc') | ||
|
||
else: | ||
# Other posix-like: Linux, Solaris, etc. | ||
# What is the proper way to detect iODBC, MyODBC, unixODBC, etc.? | ||
libraries.append('odbc') | ||
|
||
if exists('MANIFEST'): | ||
os.remove('MANIFEST') | ||
|
||
setup (name = "pyodbc", | ||
version = version_str, | ||
description = "DB API Module for ODBC", | ||
|
||
long_description = ('A Python DB API 2 module for ODBC. This project provides an up-to-date, ' | ||
'convenient interface to ODBC using native data types like datetime and decimal.'), | ||
|
||
maintainer = "Michael Kleehammer", | ||
maintainer_email = "[email protected]", | ||
|
||
ext_modules = [ Extension('pyodbc', files, | ||
libraries=libraries, | ||
define_macros = [ ('PYODBC_%s' % name, value) for name,value in zip(['MAJOR', 'MINOR', 'MICRO', 'BUILD'], version) ], | ||
extra_compile_args=extra_compile_args, | ||
extra_link_args=extra_link_args | ||
) ], | ||
|
||
classifiers = [ 'Development Status :: 5 - Production/Stable', | ||
'Intended Audience :: Developers', | ||
'Intended Audience :: System Administrators', | ||
'License :: OSI Approved :: MIT License', | ||
'Operating System :: Microsoft :: Windows', | ||
'Operating System :: POSIX', | ||
'Programming Language :: Python', | ||
'Topic :: Database', | ||
], | ||
|
||
url = 'http://pyodbc.sourceforge.net', | ||
download_url = 'http://github.com/pyodbc/pyodbc/tree/master') | ||
|
||
|
||
def get_version(): | ||
""" | ||
Returns the version of the product as (description, [major,minor,micro,beta]). | ||
If the release is official, `beta` will be 9999 (OFFICIAL_BUILD). | ||
1. If in a git repository, use the latest tag (git describe). | ||
2. If in an unzipped source directory (from setup.py sdist), | ||
read the version from the PKG-INFO file. | ||
3. Use 2.1.0.0 and complain a lot. | ||
""" | ||
# My goal is to (1) provide accurate tags for official releases but (2) not have to manage tags for every test | ||
# release. | ||
# | ||
# Official versions are tagged using 3 numbers: major, minor, micro. A build of a tagged version should produce | ||
# the version using just these pieces, such as 2.1.4. | ||
# | ||
# Unofficial versions are "working towards" the next version. So the next unofficial build after 2.1.4 would be a | ||
# beta for 2.1.5. Using 'git describe' we can find out how many changes have been made after 2.1.4 and we'll use | ||
# this count as the beta id (beta1, beta2, etc.) | ||
# | ||
# Since the 4 numbers are put into the Windows DLL, we want to make sure the beta versions sort *after* the | ||
# official, so we set the final build number to 9999, but we don't show it. | ||
|
||
name = None # branch/feature name. Should be None for official builds. | ||
numbers = None # The 4 integers that make up the version. | ||
|
||
# If this is a source release the version will have already been assigned and be in the PKG-INFO file. | ||
|
||
name, numbers = _get_version_pkginfo() | ||
|
||
# If not a source release, we should be in a git repository. Look for the latest tag. | ||
|
||
if not numbers: | ||
name, numbers = _get_version_git() | ||
|
||
if not numbers: | ||
print 'WARNING: Unable to determine version. Using 2.1.0.0' | ||
name, numbers = '2.1.0-unsupported', [2,1,0,0] | ||
|
||
return name, numbers | ||
|
||
|
||
def _get_version_pkginfo(): | ||
filename = join(dirname(abspath(__file__)), 'PKG-INFO') | ||
if exists(filename): | ||
re_ver = re.compile(r'^Version: \s+ (\d+)\.(\d+)\.(\d+) (?: -beta(\d+))?', re.VERBOSE) | ||
for line in open(filename): | ||
match = re_ver.search(line) | ||
if match: | ||
name = line.split(':', 1)[1].strip() | ||
numbers = [ int(n or 0) for n in match.groups() ] | ||
return name, numbers | ||
|
||
return None, None | ||
|
||
|
||
def _get_version_git(): | ||
n, result = getoutput('git describe --tags') | ||
if n: | ||
print 'WARNING: git describe failed with: %s %s' % (n, result) | ||
return None, None | ||
|
||
match = re.match(r'(\d+).(\d+).(\d+) (?: -(\d+)-g[0-9a-z]+)?', result, re.VERBOSE) | ||
if not match: | ||
return None, None | ||
|
||
numbers = [ int(n or OFFICIAL_BUILD) for n in match.groups() ] | ||
if numbers[-1] == OFFICIAL_BUILD: | ||
name = '%s.%s.%s' % tuple(numbers[:3]) | ||
if numbers[-1] != OFFICIAL_BUILD: | ||
# This is a beta of the next micro release, so increment the micro number to reflect this. | ||
numbers[-2] += 1 | ||
name = '%s.%s.%s-beta%s' % tuple(numbers) | ||
return name, numbers | ||
|
||
|
||
|
||
def getoutput(cmd): | ||
pipe = os.popen(cmd, 'r') | ||
text = pipe.read().rstrip('\n') | ||
status = pipe.close() or 0 | ||
return status, text | ||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
|
||
// 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. | ||
// | ||
// 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. | ||
|
||
#include "pyodbc.h" | ||
#include "buffer.h" | ||
#include "pyodbcmodule.h" | ||
|
||
Py_ssize_t | ||
PyBuffer_GetMemory(PyObject* buffer, const char** pp) | ||
{ | ||
PyBufferProcs* procs = buffer->ob_type->tp_as_buffer; | ||
|
||
if (!procs || !PyType_HasFeature(buffer->ob_type, Py_TPFLAGS_HAVE_GETCHARBUFFER)) | ||
{ | ||
// Can't access the memory directly because the buffer object doesn't support it. | ||
return -1; | ||
} | ||
|
||
if (procs->bf_getsegcount(buffer, 0) != 1) | ||
{ | ||
// Can't access the memory directly because there is more than one segment. | ||
return -1; | ||
} | ||
|
||
#if PY_VERSION_HEX >= 0x02050000 | ||
char* pT = 0; | ||
#else | ||
const char* pT = 0; | ||
#endif | ||
Py_ssize_t cb = procs->bf_getcharbuffer(buffer, 0, &pT); | ||
|
||
if (pp) | ||
*pp = pT; | ||
|
||
return cb; | ||
} | ||
|
||
Py_ssize_t | ||
PyBuffer_Size(PyObject* self) | ||
{ | ||
if (!PyBuffer_Check(self)) | ||
{ | ||
PyErr_SetString(PyExc_TypeError, "Not a buffer!"); | ||
return 0; | ||
} | ||
|
||
Py_ssize_t total_len = 0; | ||
self->ob_type->tp_as_buffer->bf_getsegcount(self, &total_len); | ||
return total_len; | ||
} |
Oops, something went wrong.