Fixed crash and win32 patches.

This commit is contained in:
Federico Di Gregorio 2007-04-11 04:16:00 +00:00
parent d6f2aa27b7
commit 2a6b523506
5 changed files with 200 additions and 43 deletions

View File

@ -1,3 +1,11 @@
2007-04-11 Federico Di Gregorio <fog@initd.org>
* psycopg/cursor_type.c: added check to raise an error when
some crazy programmer tries to use different argument formats
in the same query string. Fixes #162.
* Applied patch from David Rushby to fix win32 builds.
2007-04-10 Federico Di Gregorio <fog@initd.org>
* Applied patch from David Rushby to fix mem and ref leaks in

View File

@ -52,6 +52,17 @@ static void Dprintf(const char *fmt, ...) {}
#if defined(_WIN32) || defined(__BEOS__)
#ifdef _WIN32
/* A Python extension should be linked to only one C runtime: the same one as
* the Python interpreter itself. Straightforwardly using the strdup function
* causes MinGW to implicitly link to the msvcrt.dll, which is not appropriate
* for any Python version later than 2.3.
* Microsoft C runtimes for Windows 98 and later make a _strdup function
* available, which replaces the "normal" strdup. If we replace all psycopg
* calls to strdup with calls to _strdup, MinGW no longer implicitly links to
* the obsolete C runtime. */
#define strdup _strdup
#include <winsock2.h>
#define pthread_mutex_t HANDLE
#define pthread_condvar_t HANDLE
@ -102,7 +113,7 @@ static struct tm *localtime_r(time_t *t, struct tm *tm)
#define inline
#endif
#if defined(__FreeBSD__) || defined(_WIN32) || defined(__sun__)
#if defined(__FreeBSD__) || (defined(_WIN32) && !defined(__GNUC__)) || defined(__sun__)
/* what's this, we have no round function either? */
static double round(double num)
{

View File

@ -79,7 +79,7 @@ _mogrify(PyObject *var, PyObject *fmt, connectionObject *conn, PyObject **new)
PyObject *key, *value, *n, *item;
char *d, *c;
Py_ssize_t index = 0;
int force = 0;
int force = 0, kind = 0;
/* from now on we'll use n and replace its value in *new only at the end,
just before returning. we also init *new to NULL to exit with an error
@ -88,6 +88,15 @@ _mogrify(PyObject *var, PyObject *fmt, connectionObject *conn, PyObject **new)
c = PyString_AsString(fmt);
while(*c) {
/* check if some crazy guy mixed formats */
if (kind == 2) {
Py_XDECREF(n);
psyco_set_error(ProgrammingError, (PyObject*)conn,
"argument formats can't be mixed", NULL, NULL);
return -1;
}
kind = 1;
/* handle plain percent symbol in format string */
if (c[0] == '%' && c[1] == '%') {
c+=2; force = 1;
@ -182,6 +191,15 @@ _mogrify(PyObject *var, PyObject *fmt, connectionObject *conn, PyObject **new)
because we don't need to check the old/new dictionary for
keys */
/* check if some crazy guy mixed formats */
if (kind == 1) {
Py_XDECREF(n);
psyco_set_error(ProgrammingError, (PyObject*)conn,
"argument formats can't be mixed", NULL, NULL);
return -1;
}
kind = 2;
value = PySequence_GetItem(var, index);
/* value has refcnt inc'ed by 1 here */

View File

@ -1,5 +1,5 @@
[build_ext]
define=PSYCOPG_EXTENSIONS,PSYCOPG_DISPLAY_SIZE,PSYCOPG_NEW_BOOLEAN,HAVE_PQFREEMEM,HAVE_PQPROTOCOL3
define=PSYCOPG_EXTENSIONS,PSYCOPG_DISPLAY_SIZE,PSYCOPG_NEW_BOOLEAN,HAVE_PQFREEMEM,HAVE_PQPROTOCOL3,PSYCOPG_DEBUG
# PSYCOPG_EXTENSIONS enables extensions to PEP-249 (you really want this)
# PSYCOPG_DISPLAY_SIZE enable display size calculation (a little slower)
# HAVE_PQFREEMEM should be defined on PostgreSQL >= 7.4

154
setup.py
View File

@ -44,8 +44,10 @@ Operating System :: Unix
"""
import os
import os.path
import sys
import popen2
import ConfigParser
from distutils.core import setup, Extension
from distutils.errors import DistutilsFileError
from distutils.command.build_ext import build_ext
@ -55,6 +57,8 @@ from distutils.ccompiler import get_default_compiler
PSYCOPG_VERSION = '2.0.6b1'
version_flags = []
PLATFORM_IS_WINDOWS = sys.platform.lower().startswith('win')
# to work around older distutil limitations
if sys.version < '2.2.3':
from distutils.dist import DistributionMetadata
@ -97,35 +101,76 @@ class psycopg_build_ext(build_ext):
build_ext.initialize_options(self)
self.use_pg_dll = 1
self.pgdir = None
self.pg_config = self.DEFAULT_PG_CONFIG
self.mx_include_dir = None
self.pg_config = self.autodetect_pg_config_path()
def get_compiler(self):
"""Return the c compiler to compile extensions.
"""Return the name of the C compiler used to compile extensions.
If a compiler was not explicitely set (on the command line, for
example), fall back on the default compiler.
"""
return self.compiler or get_default_compiler()
if self.compiler:
# distutils doesn't keep the type of self.compiler uniform; we
# compensate:
if isinstance(self.compiler, str):
name = self.compiler
else:
name = self.compiler.compiler_type
else:
name = get_default_compiler()
return name
def get_pg_config(self, kind):
return get_pg_config(kind, self.pg_config)
def build_extensions(self):
# Linking against this library causes psycopg2 to crash
# on Python >= 2.4. Maybe related to strdup calls, cfr.
# http://mail.python.org/pipermail/distutils-sig/2005-April/004433.html
if self.get_compiler().compiler_type == "mingw32" \
and 'msvcr71' in self.compiler.dll_libraries:
self.compiler.dll_libraries.remove('msvcr71')
build_ext.build_extensions(self)
def finalize_win32(self):
"""Finalize build system configuration on win32 platform."""
import struct
sysVer = sys.version_info[:2]
# Add compiler-specific arguments:
extra_compiler_args = []
compiler_name = self.get_compiler().lower()
compiler_is_msvc = compiler_name.startswith('msvc')
compiler_is_mingw = compiler_name.startswith('mingw')
if compiler_is_msvc:
# If we're using MSVC 7.1 or later on a 32-bit platform, add the
# /Wp64 option to generate warnings about Win64 portability
# problems.
if sysVer >= (2,4) and struct.calcsize('P') == 4:
extra_compiler_args.append('/Wp64')
elif compiler_is_mingw:
# Default MinGW compilation of Python extensions on Windows uses
# only -O:
extra_compiler_args.append('-O3')
# GCC-compiled Python on non-Windows platforms is built with strict
# aliasing disabled, but that must be done explicitly on Windows to
# avoid large numbers of warnings for perfectly idiomatic Python C
# API code.
extra_compiler_args.append('-fno-strict-aliasing')
# Force correct C runtime library linkage:
if sysVer <= (2,3):
# Yes: 'msvcr60', rather than 'msvcrt', is the correct value
# on the line below:
self.libraries.append('msvcr60')
elif sysVer in ((2,4), (2,5)):
self.libraries.append('msvcr71')
# Beyond Python 2.5, we take our chances on the default C runtime
# library, because we don't know what compiler those future
# versions of Python will use.
for exten in ext: # ext is a global list of Extension objects
exten.extra_compile_args.extend(extra_compiler_args)
# End of add-compiler-specific arguments section.
self.libraries.append("ws2_32")
self.libraries.append("advapi32")
if self.get_compiler() == "msvc":
if compiler_is_msvc:
# MSVC requires an explicit "libpq"
self.libraries.remove("pq")
self.libraries.append("libpq")
@ -172,6 +217,82 @@ class psycopg_build_ext(build_ext):
if hasattr(self, "finalize_" + sys.platform):
getattr(self, "finalize_" + sys.platform)()
def autodetect_pg_config_path(self):
res = None
if PLATFORM_IS_WINDOWS:
res = self.autodetect_pg_config_path_windows()
return res or self.DEFAULT_PG_CONFIG
def autodetect_pg_config_path_windows(self):
# Find the first PostgreSQL installation listed in the registry and
# return the full path to its pg_config utility.
#
# This autodetection is performed *only* if the following conditions
# hold:
#
# 1) The pg_config utility is not already available on the PATH:
if os.popen('pg_config').close() is None: # .close()->None == success
return None
# 2) The user has not specified any of the following settings in
# setup.cfg:
# - pg_config
# - include_dirs
# - library_dirs
for settingName in ('pg_config', 'include_dirs', 'library_dirs'):
try:
val = parser.get('build_ext', settingName)
except ConfigParser.NoOptionError:
pass
else:
if val.strip() != '':
return None
# end of guard conditions
import _winreg
pg_inst_base_dir = None
pg_config_path = None
reg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE)
pg_inst_list_key = _winreg.OpenKey(reg,
'SOFTWARE\\PostgreSQL\\Installations'
)
try:
# Determine the name of the first subkey, if any:
try:
first_sub_key_name = _winreg.EnumKey(pg_inst_list_key, 0)
except EnvironmentError:
first_sub_key_name = None
if first_sub_key_name is not None:
pg_first_inst_key = _winreg.OpenKey(reg,
'SOFTWARE\\PostgreSQL\\Installations\\'
+ first_sub_key_name
)
try:
pg_inst_base_dir = _winreg.QueryValueEx(
pg_first_inst_key, 'Base Directory'
)[0]
finally:
_winreg.CloseKey(pg_first_inst_key)
finally:
_winreg.CloseKey(pg_inst_list_key)
if pg_inst_base_dir and os.path.exists(pg_inst_base_dir):
pg_config_path = os.path.join(pg_inst_base_dir, 'bin',
'pg_config.exe'
)
# Support unicode paths, if this version of Python provides the
# necessary infrastructure:
if hasattr(sys, 'getfilesystemencoding'):
pg_config_path = pg_config_path.encode(
sys.getfilesystemencoding()
)
return pg_config_path
# let's start with macro definitions (the ones not already in setup.cfg)
define_macros = []
include_dirs = []
@ -196,8 +317,7 @@ sources = [
'adapter_qstring.c', 'adapter_pboolean.c', 'adapter_binary.c',
'adapter_asis.c', 'adapter_list.c']
from ConfigParser import ConfigParser
parser = ConfigParser()
parser = ConfigParser.ConfigParser()
parser.read('setup.cfg')
# Choose if to use Decimal type
@ -259,7 +379,7 @@ if version_flags:
else:
PSYCOPG_VERSION_EX = PSYCOPG_VERSION
if sys.platform != 'win32':
if not PLATFORM_IS_WINDOWS:
define_macros.append(('PSYCOPG_VERSION', '"'+PSYCOPG_VERSION_EX+'"'))
else:
define_macros.append(('PSYCOPG_VERSION', '\\"'+PSYCOPG_VERSION_EX+'\\"'))