Re: Segentation faults when connecting to SQL Server 2000
Kevin Jacobs <[email protected]>
| Newsgroups | gmane.comp.python.sybase |
|---|---|
| Message-ID | <[email protected]> |
On Tue, 10 Sep 2002, Harri Pasanen wrote: > I experienced similar things. Probably if you change the query order, it will > still be so that the first one works. So the problem is that the connection > / cursors keep some state that throws it off balance. > > I managed to work around this by closing the cursor and reallocating a new one > for the next query. And having opened the connection with 'auto_commit=1' > also helped. Attached is a _very_ experimental patch that re-works some of the connection state logic and locking in the Sybase.py module. Please apply it to an original copy of Sybase.py, and let me know how it goes. With it, I am able to run many queries in sequence very reliably. Unfortunately, I don't have a Sybase installation to test, so I don't know exactly where the FreeTDS implementation of libCT seems to be diverging from what must obviously be robust for many Sybase users. Good luck, -Kevin -- Kevin Jacobs The OPAL Group - Enterprise Systems Architect Voice: (216) 986-0710 x 19 E-mail: [email protected] Fax: (216) 986-0714 WWW: http://www.theopalgroup.com
diff
(text/plain, 5.6 KB)
--- /home/jacobs/projects/MSSQL/sybase-0.35pre1/Sybase.py Sun Apr 21 02:00:03 2002
+++ Sybase.py Mon Jul 15 09:21:38 2002
@@ -136,7 +136,7 @@
raise DatabaseError(_fmt_client(msg))
def _servermsg_cb(ctx, conn, msg):
- if msg.msgnumber not in (5701,):
+ if msg.msgnumber not in (5701,5703):
raise DatabaseError(_fmt_server(msg))
def _row_bind(cmd, count = 1):
@@ -231,6 +231,7 @@
self._owner = owner
self._state = _CUR_IDLE
self._lock_count = 0
+ self._channel_lock_held = 0
self._lock()
try:
status, self._cmd = owner._conn.ct_cmd_alloc()
@@ -258,12 +259,28 @@
def _unlock(self):
self._owner._lock.release()
self._lock_count = self._lock_count - 1
+ #assert not self._channel_lock_held or self._lock_count > 0
+
+ def _lock_channel(self):
+ assert self._lock_count > 0
+ assert self._state == _CUR_IDLE
+ assert not self._channel_lock_held
+ self._lock()
+ self._channel_lock_held = 1
+
+ def _unlock_channel(self):
+ assert self._channel_lock_held
+ assert self._state in (_CUR_IDLE,_CUR_CLOSED)
+ assert self._lock_count > 1
+ self._channel_lock_held = 0
+ self._unlock()
def _raise_error(self, exc, text):
if self._state not in (_CUR_IDLE, _CUR_CLOSED):
- if self._owner._conn.ct_cancel(CS_CANCEL_ALL) == CS_SUCCEED:
+ if self._owner and self._owner._conn and \
+ self._owner._conn.ct_cancel(CS_CANCEL_ALL) == CS_SUCCEED:
self._state = _CUR_IDLE
- self._unlock()
+ self._unlock_channel()
raise exc(text)
def callproc(self, name, params = ()):
@@ -279,7 +296,7 @@
# At the start of a command acquire an extra lock -
# when the cursor is idle again the extra lock will be
# released.
- self._lock()
+ self._lock_channel()
status = self._cmd.ct_command(CS_RPC_CMD, name)
if status != CS_SUCCEED:
self._raise_error(Error, 'ct_command')
@@ -314,9 +331,13 @@
if self._state != _CUR_IDLE:
status = self._cmd.ct_cancel(CS_CANCEL_ALL)
if status == CS_SUCCEED:
- self._unlock()
+ self._state = _CUR_IDLE
+ self._unlock_channel()
+ else:
+ self._raise_error(Error, 'ct_cancel')
self._cmd = None
self._state = _CUR_CLOSED
+ assert not self._channel_lock_held
finally:
self._unlock()
@@ -332,7 +353,7 @@
# At the start of a command acquire an extra lock - when
# the cursor is idle again the extra lock will be
# released.
- self._lock()
+ self._lock_channel()
self._cmd.ct_command(CS_LANG_CMD, sql)
for name, value in params.items():
buf = DataBuf(value)
@@ -363,7 +384,7 @@
self._lock()
try:
if self._state == _CUR_IDLE:
- return
+ self._raise_error(ProgrammingError, 'no result set pending')
if self._state == _CUR_CLOSED:
self._raise_error(ProgrammingError, 'cursor is closed')
if self._state == _CUR_FETCHING:
@@ -373,7 +394,7 @@
status = self._cmd.ct_cancel(CS_CANCEL_ALL)
if status == CS_SUCCEED:
self._state = _CUR_IDLE
- self._unlock()
+ self._unlock_channel()
raise
if row:
return row
@@ -444,10 +465,10 @@
pass
def _fetch_rowcount(self):
+ self.rowcount = -1
status, result = self._cmd.ct_results()
if status == CS_END_RESULTS:
- self._state = _CUR_IDLE
- self._unlock()
+ self.rowcount = 0
return
elif status != CS_SUCCEED:
self._raise_error(Error, 'ct_results')
@@ -459,11 +480,14 @@
self._raise_error(Error, 'ct_results')
def _start_results(self):
+ self.rowcount = -1
while 1:
status, result = self._cmd.ct_results()
if status == CS_END_RESULTS:
- self._state = _CUR_IDLE
- self._unlock()
+ self.rowcount = 0
+ if self._state != _CUR_IDLE:
+ self._state = _CUR_IDLE
+ self._unlock_channel()
return
elif status != CS_SUCCEED:
self._raise_error(Error, 'ct_results')
@@ -481,6 +505,7 @@
elif result in (CS_CMD_DONE, CS_CMD_SUCCEED):
status, self.rowcount = self._cmd.ct_res_info(CS_ROW_COUNT)
if status != CS_SUCCEED:
+ self.rowcount = -1
self._raise_error(Error, 'ct_res_info')
else:
self._raise_error(Error, 'ct_results')
@@ -562,9 +587,10 @@
def close(self):
'''DBI-API Connection.close()
'''
- conn = self._conn
self._lock.acquire()
try:
+ conn = self._conn
+ self._conn = None
status, result = conn.ct_con_props(CS_GET, CS_CON_STATUS)
if status != CS_SUCCEED:
self._raise_error(Error, 'ct_con_props')