PageRenderTime 62ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/External.LCA_RESTRICTED/Languages/IronPython/27/Lib/site-packages/adodbapi/adodbapi.py

http://github.com/IronLanguages/main
Python | 1308 lines | 1240 code | 10 blank | 58 comment | 58 complexity | 5385a65f69a434559cdb07e316a843cb MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  1. """adodbapi v2.2.6 - A python DB API 2.0 interface to Microsoft ADO
  2. Copyright (C) 2002 Henrik Ekelund
  3. Email: <http://sourceforge.net/sendmessage.php?touser=618411>
  4. This library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. This library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with this library; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  15. version 2.1 (and later) by Vernon Cole -- update for Decimal data type
  16. (requires Python 2.4 or above or or Python 2.3 with "import win32com.decimal_23")
  17. all uses of "verbose" below added by Cole for v2.1
  18. """
  19. # N.O.T.E.:...
  20. # if you have been using an older version of adodbapi and are getting errors because
  21. # numeric and monitary data columns are now returned as Decimal data,
  22. # try adding the following line to get that data as strings: ...
  23. #adodbapi.variantConversions[adodbapi.adoExactNumericTypes]=adodbapi.cvtString # get currency as strings
  24. import string
  25. import time
  26. import calendar
  27. import types
  28. import sys
  29. import traceback
  30. import datetime
  31. try:
  32. from exceptions import StandardError as _BaseException
  33. except ImportError:
  34. # py3k
  35. _BaseException = Exception
  36. try:
  37. import decimal
  38. except ImportError: #perhaps running Cpython 2.3
  39. import win32com.decimal_23 as decimal
  40. try:
  41. import win32com.client
  42. onIronPython = False
  43. except ImportError: # implies running on IronPython
  44. onIronPython = True
  45. # --- define objects to smooth out IronPython <-> CPython differences
  46. if onIronPython:
  47. from System import Activator, Type, DBNull, DateTime, Array, Byte
  48. from System import Decimal as SystemDecimal
  49. from clr import Reference
  50. def Dispatch(dispatch):
  51. type = Type.GetTypeFromProgID(dispatch)
  52. return Activator.CreateInstance(type)
  53. def getIndexedValue(obj,index):
  54. return obj.Item[index]
  55. else: #pywin32
  56. import pythoncom
  57. import pywintypes
  58. pythoncom.__future_currency__ = True
  59. def Dispatch(dispatch):
  60. return win32com.client.Dispatch(dispatch)
  61. def getIndexedValue(obj,index):
  62. return obj(index)
  63. DBNull = type(None)
  64. DateTime = type(NotImplemented) #impossible value
  65. # --- define objects to smooth out Python3000 <-> Python 2.x differences
  66. unicodeType = unicode #this line will be altered by 2to3.py to '= str'
  67. longType = long #thil line will be altered by 2to3.py to '= int'
  68. memoryViewType = types.BufferType #will be altered to '= memoryview'
  69. if sys.version[0] == '3':
  70. StringTypes = [str]
  71. makeByteBuffer = bytes
  72. else:
  73. makeByteBuffer = buffer
  74. bytes = str
  75. StringTypes = types.StringTypes # will be messed up by 2to3 but never used
  76. def standardErrorHandler(connection,cursor,errorclass,errorvalue):
  77. err=(errorclass,errorvalue)
  78. connection.messages.append(err)
  79. if cursor!=None:
  80. cursor.messages.append(err)
  81. raise errorclass(errorvalue)
  82. class TimeConverter(object):
  83. def __init__(self):
  84. self._ordinal_1899_12_31=datetime.date(1899,12,31).toordinal()-1
  85. #Use self.types to compare if an input parameter is a datetime
  86. self.types = (type(self.Date(2000,1,1)),
  87. type(self.Time(12,1,1)),
  88. type(self.Timestamp(2000,1,1,12,1,1)))
  89. def COMDate(self,obj):
  90. 'Returns a ComDate from a datetime in inputformat'
  91. raise NotImplementedError #"Abstract class"
  92. def DateObjectFromCOMDate(self,comDate):
  93. 'Returns an object of the wanted type from a ComDate'
  94. raise NotImplementedError #"Abstract class"
  95. def Date(self,year,month,day):
  96. "This function constructs an object holding a date value. "
  97. raise NotImplementedError #"Abstract class"
  98. def Time(self,hour,minute,second):
  99. "This function constructs an object holding a time value. "
  100. raise NotImplementedError #"Abstract class"
  101. def Timestamp(self,year,month,day,hour,minute,second):
  102. "This function constructs an object holding a time stamp value. "
  103. raise NotImplementedError #"Abstract class"
  104. def DateObjectToIsoFormatString(self,obj):
  105. "This function should return a string in the format 'YYYY-MM-dd HH:MM:SS:ms' (ms optional) "
  106. raise NotImplementedError #"Abstract class"
  107. class mxDateTimeConverter(TimeConverter):
  108. def COMDate(self,obj):
  109. return obj.COMDate()
  110. def DateObjectFromCOMDate(self,comDate):
  111. return mx.DateTime.DateTimeFromCOMDate(comDate)
  112. def Date(self,year,month,day):
  113. return mx.DateTime.Date(year,month,day)
  114. def Time(self,hour,minute,second):
  115. return mx.DateTime.Time(hour,minute,second)
  116. def Timestamp(self,year,month,day,hour,minute,second):
  117. return mx.DateTime.Timestamp(year,month,day,hour,minute,second)
  118. def DateObjectToIsoFormatString(self,obj):
  119. return obj.Format('%Y-%m-%d %H:%M:%S')
  120. class pythonDateTimeConverter(TimeConverter): # datetime module is available in Python 2.3
  121. def __init__(self):
  122. TimeConverter.__init__(self)
  123. def COMDate(self,obj):
  124. tt=obj.timetuple()
  125. try:
  126. ms=obj.microsecond
  127. except:
  128. ms=0
  129. YMDHMSmsTuple=tuple(tt[:6] + (ms,))
  130. return self.COMDateFromTuple(YMDHMSmsTuple)
  131. def DateObjectFromCOMDate(self,comDate):
  132. #ComDate is number of days since 1899-12-31
  133. if isinstance(comDate,datetime.datetime):
  134. return comDate.replace(tzinfo=None) # make non aware
  135. elif isinstance(comDate,DateTime):
  136. fComDate = comDate.ToOADate()
  137. else:
  138. fComDate=float(comDate)
  139. millisecondsperday=86400000 # 24*60*60*1000
  140. integerPart = int(fComDate)
  141. floatpart=fComDate-integerPart
  142. if floatpart == 0.0:
  143. return datetime.date.fromordinal(integerPart + self._ordinal_1899_12_31)
  144. dte=datetime.datetime.fromordinal(integerPart + self._ordinal_1899_12_31) \
  145. + datetime.timedelta(milliseconds=floatpart*millisecondsperday)
  146. return dte
  147. def Date(self,year,month,day):
  148. return datetime.date(year,month,day)
  149. def Time(self,hour,minute,second):
  150. return datetime.time(hour,minute,second)
  151. def Timestamp(self,year,month,day,hour,minute,second):
  152. return datetime.datetime(year,month,day,hour,minute,second)
  153. def COMDateFromTuple(self,YMDHMSmsTuple):
  154. d = datetime.date(YMDHMSmsTuple[0],YMDHMSmsTuple[1],YMDHMSmsTuple[2])
  155. integerPart = d.toordinal() - self._ordinal_1899_12_31
  156. ms = ((YMDHMSmsTuple[3]*60 \
  157. +YMDHMSmsTuple[4])*60 \
  158. +YMDHMSmsTuple[5])*1000 \
  159. +YMDHMSmsTuple[6]
  160. fractPart = ms / 86400000.0
  161. return integerPart + fractPart
  162. def DateObjectToIsoFormatString(self,obj):
  163. if isinstance(obj,datetime.datetime):
  164. s = obj.strftime('%Y-%m-%d %H:%M:%S')
  165. elif isinstance(obj,datetime.date): #exact midnight
  166. s = obj.strftime('%Y-%m-%d 00:00:00')
  167. else:
  168. try: #usually datetime.datetime
  169. s = obj.isoformat()
  170. except: #but may be mxdatetime
  171. s = obj.Format('%Y-%m-%d %H:%M:%S')
  172. return s
  173. class pythonTimeConverter(TimeConverter):
  174. def __init__(self):
  175. TimeConverter.__init__(self)
  176. def COMDate(self,timeobj):
  177. return self.COMDateFromTuple(timeobj)
  178. def COMDateFromTuple(self,t):
  179. d = datetime.date(t[0],t[1],t[2])
  180. integerPart = d.toordinal() - self._ordinal_1899_12_31
  181. sec = (t[3]*60 + t[4])*60 + t[5]
  182. fractPart = sec / 86400.0
  183. return integerPart + fractPart
  184. def DateObjectFromCOMDate(self,comDate):
  185. 'Returns ticks since 1970'
  186. if isinstance(comDate,datetime.datetime):
  187. return comDate.timetuple()
  188. elif isinstance(comDate,DateTime):
  189. fcomDate = comDate.ToOADate()
  190. else:
  191. fcomDate = float(comDate)
  192. secondsperday=86400 # 24*60*60
  193. #ComDate is number of days since 1899-12-31, gmtime epoch is 1970-1-1 = 25569 days
  194. t=time.gmtime(secondsperday*(fcomDate-25569.0))
  195. return t #year,month,day,hour,minute,second,weekday,julianday,daylightsaving=t
  196. def Date(self,year,month,day):
  197. return self.Timestamp(year,month,day,0,0,0)
  198. def Time(self,hour,minute,second):
  199. return time.gmtime((hour*60+minute)*60 + second)
  200. def Timestamp(self,year,month,day,hour,minute,second):
  201. return time.localtime(time.mktime((year,month,day,hour,minute,second,0,0,-1)))
  202. def DateObjectToIsoFormatString(self,obj):
  203. try:
  204. s = time.strftime('%Y-%m-%d %H:%M:%S',obj)
  205. except:
  206. s = obj.strftime('%Y-%m-%d')
  207. return s
  208. class Error(_BaseException):
  209. pass #Exception that is the base class of all other error
  210. #exceptions. You can use this to catch all errors with one
  211. #single 'except' statement. Warnings are not considered
  212. #errors and thus should not use this class as base. It must
  213. #be a subclass of the Python StandardError (defined in the
  214. #module exceptions).
  215. class Warning(_BaseException):
  216. pass
  217. class InterfaceError(Error):
  218. pass
  219. class DatabaseError(Error):
  220. pass
  221. class InternalError(DatabaseError):
  222. pass
  223. class OperationalError(DatabaseError):
  224. pass
  225. class ProgrammingError(DatabaseError):
  226. pass
  227. class IntegrityError(DatabaseError):
  228. pass
  229. class DataError(DatabaseError):
  230. pass
  231. class NotSupportedError(DatabaseError):
  232. pass
  233. verbose = False
  234. version = __doc__.split('-',2)[0] #v2.1 Cole
  235. def connect(connstr, timeout=30): #v2.1 Simons
  236. "Connection string as in the ADO documentation, SQL timeout in seconds"
  237. try:
  238. if not onIronPython:
  239. pythoncom.CoInitialize() #v2.1 Paj
  240. conn=Dispatch('ADODB.Connection') #connect _after_ CoIninialize v2.1.1 adamvan
  241. except:
  242. raise InterfaceError #Probably COM Error
  243. try:
  244. conn.CommandTimeout=timeout #v2.1 Simons
  245. conn.ConnectionString=connstr
  246. except:
  247. raise Error
  248. if verbose:
  249. print '%s attempting: "%s"' % (version,connstr)
  250. try:
  251. conn.Open()
  252. except (Exception), e:
  253. raise DatabaseError(e)
  254. return Connection(conn)
  255. apilevel='2.0' #String constant stating the supported DB API level.
  256. threadsafety=1
  257. # Integer constant stating the level of thread safety the interface supports,
  258. # 1 = Threads may share the module, but not connections.
  259. # TODO: Have not tried this, maybe it is better than 1?
  260. ##
  261. ## Possible values are:
  262. ##0 = Threads may not share the module.
  263. ##1 = Threads may share the module, but not connections.
  264. ##2 = Threads may share the module and connections.
  265. ##3 = Threads may share the module, connections and cursors.
  266. paramstyle='qmark'
  267. #String constant stating the type of parameter marker formatting expected by the interface.
  268. # 'qmark' = Question mark style, e.g. '...WHERE name=?'
  269. adXactBrowse =0x100 # from enum IsolationLevelEnum
  270. adXactChaos =0x10 # from enum IsolationLevelEnum
  271. adXactCursorStability =0x1000 # from enum IsolationLevelEnum
  272. adXactIsolated =0x100000 # from enum IsolationLevelEnum
  273. adXactReadCommitted =0x1000 # from enum IsolationLevelEnum
  274. adXactReadUncommitted =0x100 # from enum IsolationLevelEnum
  275. adXactRepeatableRead =0x10000 # from enum IsolationLevelEnum
  276. adXactSerializable =0x100000 # from enum IsolationLevelEnum
  277. defaultIsolationLevel=adXactReadCommitted
  278. # Set defaultIsolationLevel on module level before creating the connection.
  279. # It may be one of the above
  280. # if you simply "import adodbapi", you'll say:
  281. # "adodbapi.adodbapi.defaultIsolationLevel=adodbapi.adodbapi.adXactBrowse", for example
  282. adUseClient = 3 # from enum CursorLocationEnum #v2.1 Rose
  283. adUseServer = 2 # from enum CursorLocationEnum #v2.1 Rose
  284. defaultCursorLocation=adUseServer #v2.1 Rose
  285. # Set defaultCursorLocation on module level before creating the connection.
  286. # It may be one of the above
  287. class Connection(object):
  288. # include connection attributes required by api definition.
  289. Warning = Warning
  290. Error = Error
  291. InterfaceError = InterfaceError
  292. DataError = DataError
  293. DatabaseError = DatabaseError
  294. OperationalError = OperationalError
  295. IntegrityError = IntegrityError
  296. InternalError = InternalError
  297. NotSupportedError = NotSupportedError
  298. ProgrammingError = ProgrammingError
  299. def __init__(self,adoConn):
  300. self.adoConn=adoConn
  301. self.supportsTransactions=False
  302. for indx in range(adoConn.Properties.Count):
  303. name = getIndexedValue(adoConn.Properties,indx).Name
  304. if name == 'Transaction DDL':
  305. if getIndexedValue(adoConn.Properties,indx).Value != 0: #v2.1 Albrecht
  306. self.supportsTransactions=True
  307. break
  308. self.adoConn.CursorLocation = defaultCursorLocation #v2.1 Rose
  309. if self.supportsTransactions:
  310. self.adoConn.IsolationLevel=defaultIsolationLevel
  311. self.adoConn.BeginTrans() #Disables autocommit
  312. self.errorhandler=None
  313. self.messages=[]
  314. if verbose:
  315. print 'adodbapi New connection at %X' % id(self)
  316. def _raiseConnectionError(self,errorclass,errorvalue):
  317. eh=self.errorhandler
  318. if eh==None:
  319. eh=standardErrorHandler
  320. eh(self,None,errorclass,errorvalue)
  321. def _closeAdoConnection(self): #all v2.1 Rose
  322. """close the underlying ADO Connection object,
  323. rolling it back first if it supports transactions."""
  324. if self.supportsTransactions:
  325. self.adoConn.RollbackTrans()
  326. self.adoConn.Close()
  327. if verbose:
  328. print 'adodbapi Closed connection at %X' % id(self)
  329. def close(self):
  330. """Close the connection now (rather than whenever __del__ is called).
  331. The connection will be unusable from this point forward;
  332. an Error (or subclass) exception will be raised if any operation is attempted with the connection.
  333. The same applies to all cursor objects trying to use the connection.
  334. """
  335. self.messages=[]
  336. try:
  337. self._closeAdoConnection() #v2.1 Rose
  338. except (Exception), e:
  339. self._raiseConnectionError(InternalError,e)
  340. if not onIronPython:
  341. pythoncom.CoUninitialize() #v2.1 Paj
  342. def commit(self):
  343. """Commit any pending transaction to the database.
  344. Note that if the database supports an auto-commit feature,
  345. this must be initially off. An interface method may be provided to turn it back on.
  346. Database modules that do not support transactions should implement this method with void functionality.
  347. """
  348. self.messages=[]
  349. try:
  350. if self.supportsTransactions:
  351. self.adoConn.CommitTrans()
  352. if not(self.adoConn.Attributes & adXactCommitRetaining):
  353. #If attributes has adXactCommitRetaining it performs retaining commits that is,
  354. #calling CommitTrans automatically starts a new transaction. Not all providers support this.
  355. #If not, we will have to start a new transaction by this command:
  356. self.adoConn.BeginTrans()
  357. except (Exception), e:
  358. self._raiseConnectionError(Error,e)
  359. def rollback(self):
  360. """In case a database does provide transactions this method causes the the database to roll back to
  361. the start of any pending transaction. Closing a connection without committing the changes first will
  362. cause an implicit rollback to be performed.
  363. If the database does not support the functionality required by the method, the interface should
  364. throw an exception in case the method is used.
  365. The preferred approach is to not implement the method and thus have Python generate
  366. an AttributeError in case the method is requested. This allows the programmer to check for database
  367. capabilities using the standard hasattr() function.
  368. For some dynamically configured interfaces it may not be appropriate to require dynamically making
  369. the method available. These interfaces should then raise a NotSupportedError to indicate the
  370. non-ability to perform the roll back when the method is invoked.
  371. """
  372. self.messages=[]
  373. if self.supportsTransactions:
  374. self.adoConn.RollbackTrans()
  375. if not(self.adoConn.Attributes & adXactAbortRetaining):
  376. #If attributes has adXactAbortRetaining it performs retaining aborts that is,
  377. #calling RollbackTrans automatically starts a new transaction. Not all providers support this.
  378. #If not, we will have to start a new transaction by this command:
  379. self.adoConn.BeginTrans()
  380. else:
  381. self._raiseConnectionError(NotSupportedError,None)
  382. #TODO: Could implement the prefered method by havins two classes,
  383. # one with trans and one without, and make the connect function choose which one.
  384. # the one without transactions should not implement rollback
  385. def cursor(self):
  386. "Return a new Cursor Object using the connection."
  387. self.messages=[]
  388. return Cursor(self)
  389. def printADOerrors(self):
  390. j=self.adoConn.Errors.Count
  391. if j:
  392. print 'ADO Errors:(%i)' % j
  393. for i in range(j):
  394. e=self.adoConn.Errors[i]
  395. print 'Description: %s' % e.Description
  396. print 'Number: %s ' % e.Number
  397. try:
  398. print 'Number constant:' % adoErrors[e.Number]
  399. except:
  400. pass
  401. print 'Source: %s' %e.Source
  402. print 'NativeError: %s' %e.NativeError
  403. print 'SQL State: %s' %e.SQLState
  404. if e.Number == -2147217871:
  405. print ' Error means that the Query timed out.\n Try using adodbpi.connect(constr,timeout=Nseconds)'
  406. def __del__(self):
  407. try:
  408. self._closeAdoConnection() #v2.1 Rose
  409. except:
  410. pass
  411. self.adoConn=None
  412. class Cursor(object):
  413. description=None
  414. ## This read-only attribute is a sequence of 7-item sequences.
  415. ## Each of these sequences contains information describing one result column:
  416. ## (name, type_code, display_size, internal_size, precision, scale, null_ok).
  417. ## This attribute will be None for operations that do not return rows or if the
  418. ## cursor has not had an operation invoked via the executeXXX() method yet.
  419. ## The type_code can be interpreted by comparing it to the Type Objects specified in the section below.
  420. rowcount = -1
  421. ## This read-only attribute specifies the number of rows that the last executeXXX() produced
  422. ## (for DQL statements like select) or affected (for DML statements like update or insert).
  423. ## The attribute is -1 in case no executeXXX() has been performed on the cursor or
  424. ## the rowcount of the last operation is not determinable by the interface.[7]
  425. arraysize=1
  426. ## This read/write attribute specifies the number of rows to fetch at a time with fetchmany().
  427. ## It defaults to 1 meaning to fetch a single row at a time.
  428. ## Implementations must observe this value with respect to the fetchmany() method,
  429. ## but are free to interact with the database a single row at a time.
  430. ## It may also be used in the implementation of executemany().
  431. def __init__(self,connection):
  432. self.messages=[]
  433. self.conn=connection
  434. self.rs=None
  435. self.description=None
  436. self.errorhandler=connection.errorhandler
  437. if verbose:
  438. print 'adodbapi New cursor at %X on conn %X' % (id(self),id(self.conn))
  439. def __iter__(self): # [2.1 Zamarev]
  440. return iter(self.fetchone, None) # [2.1 Zamarev]
  441. def _raiseCursorError(self,errorclass,errorvalue):
  442. eh=self.errorhandler
  443. if eh==None:
  444. eh=standardErrorHandler
  445. eh(self.conn,self,errorclass,errorvalue)
  446. def callproc(self, procname, parameters=None):
  447. """Call a stored database procedure with the given name.
  448. The sequence of parameters must contain one entry for each argument that the procedure expects.
  449. The result of the call is returned as modified copy of the input sequence.
  450. Input parameters are left untouched, output and input/output parameters replaced
  451. with possibly new values.
  452. The procedure may also provide a result set as output, which is
  453. then available through the standard fetchXXX() methods.
  454. """
  455. self.messages=[]
  456. return self._executeHelper(procname,True,parameters)
  457. def _returnADOCommandParameters(self,adoCommand):
  458. retLst=[]
  459. for i in range(adoCommand.Parameters.Count):
  460. p=getIndexedValue(adoCommand.Parameters,i)
  461. if verbose > 2:
  462. print 'return', p.Name, p.Type, p.Direction, repr(p.Value)
  463. type_code=p.Type
  464. pyObject=convertVariantToPython(p.Value,type_code)
  465. if p.Direction == adParamReturnValue:
  466. self.returnValue=pyObject
  467. else:
  468. retLst.append(pyObject)
  469. return retLst
  470. def _makeDescriptionFromRS(self,rs):
  471. self.rs = rs #v2.1.1 bkline
  472. if not rs:
  473. self.description = None
  474. elif rs.State == adStateClosed:
  475. self.description = None
  476. else:
  477. # Since the current implementation has a forward-only cursor, RecordCount will always return -1
  478. # The ADO documentation hints that obtaining the recordcount may be timeconsuming
  479. # "If the Recordset object does not support approximate positioning, this property
  480. # may be a significant drain on resources # [ekelund]
  481. # Therefore, COM will not return rowcount in most cases. [Cole]
  482. # Switching to client-side cursors will force a static cursor,
  483. # and rowcount will then be set accurately [Cole]
  484. nOfFields=rs.Fields.Count
  485. self.description=[]
  486. for i in range(nOfFields):
  487. f=getIndexedValue(rs.Fields,i)
  488. name=f.Name
  489. type_code=f.Type
  490. if not(rs.EOF or rs.BOF):
  491. display_size=f.ActualSize #TODO: Is this the correct defintion according to the DB API 2 Spec ?
  492. else:
  493. display_size=None
  494. internal_size=f.DefinedSize
  495. precision=f.Precision
  496. scale=f.NumericScale
  497. null_ok= bool(f.Attributes & adFldMayBeNull) #v2.1 Cole
  498. self.description.append((name, type_code, display_size, internal_size, precision, scale, null_ok))
  499. def close(self):
  500. """Close the cursor now (rather than whenever __del__ is called).
  501. The cursor will be unusable from this point forward; an Error (or subclass)
  502. exception will be raised if any operation is attempted with the cursor.
  503. """
  504. self.messages=[]
  505. self.conn = None #this will make all future method calls on me throw an exception
  506. if self.rs and self.rs.State != adStateClosed: # rs exists and is open #v2.1 Rose
  507. self.rs.Close() #v2.1 Rose
  508. self.rs = None #let go of the recordset so ADO will let it be disposed #v2.1 Rose
  509. # ------------------------
  510. # a note about Strategies:
  511. # Ekelund struggled to find ways to keep ADO happy with passed parameters.
  512. # He finally decided to try four "strategies" of parameter passing:
  513. # 1. Let COM define the parameter list & pass date-times in COMdate format
  514. # 2. Build a parameter list with python & pass date-times in COMdate format
  515. # 3. Let COM define the parameter list & pass date-times as ISO date strings.
  516. # 4. Build a parameter list with python & pass date-times as ISO date strings.
  517. # For each "execute" call, he would try each way, then pass all four sets of error
  518. # messages back if all four attempts failed.
  519. # My optimization is as follows:
  520. # 1. Try to use the COM parameter list.
  521. # 2. If the Refresh() call blows up, then build a perameter list
  522. # 3. If the python data is a date but the ADO is a string,
  523. # or we built the parameter list,
  524. # then pass date-times as ISO dates,
  525. # otherwise, convert to a COM date.
  526. # -- Vernon Cole v2.1
  527. # (code in executeHelper freely reformatted by me)
  528. #---------------------
  529. def _executeHelper(self,operation,isStoredProcedureCall,parameters=None):
  530. if self.conn == None:
  531. self._raiseCursorError(Error,None)
  532. return
  533. returnValueIndex=None
  534. if verbose > 1 and parameters:
  535. print 'adodbapi parameters=',repr(parameters)
  536. parmIndx=-1
  537. try:
  538. self.cmd=Dispatch("ADODB.Command")
  539. self.cmd.ActiveConnection=self.conn.adoConn
  540. self.cmd.CommandTimeout = self.conn.adoConn.CommandTimeout #v2.1 Simons
  541. self.cmd.CommandText=operation
  542. if isStoredProcedureCall:
  543. self.cmd.CommandType=adCmdStoredProc
  544. else:
  545. self.cmd.CommandType=adCmdText
  546. returnValueIndex=-1 # Initialize to impossible value
  547. if parameters != None:
  548. try: # attempt to use ADO's parameter list
  549. self.cmd.Parameters.Refresh()
  550. defaultParameterList = False
  551. except: # if it blows up
  552. defaultParameterList = True
  553. if defaultParameterList: #-- build own parameter list
  554. if verbose:
  555. print 'error in COM Refresh(). adodbapi building default parameter list'
  556. for i,elem in enumerate(parameters):
  557. name='p%i' % i
  558. adotype = pyTypeToADOType(elem)
  559. p=self.cmd.CreateParameter(name,adotype) # Name, Type, Direction, Size, Value
  560. if isStoredProcedureCall:
  561. p.Direction=adParamUnknown
  562. self.cmd.Parameters.Append(p)
  563. if verbose > 2:
  564. for i in range(self.cmd.Parameters.Count):
  565. P = self.cmd.Parameters[i]
  566. print 'adodbapi parameter attributes=', P.Name, P.Type, P.Direction, P.Size
  567. if isStoredProcedureCall:
  568. cnt=self.cmd.Parameters.Count
  569. if cnt!=len(parameters):
  570. for i in range(cnt):
  571. dir = getIndexedValue(self.cmd.Parameters,i).Direction
  572. if dir == adParamReturnValue:
  573. returnValueIndex=i
  574. break
  575. for elem in parameters:
  576. parmIndx+=1
  577. if parmIndx == returnValueIndex:
  578. parmIndx+=1
  579. p=getIndexedValue(self.cmd.Parameters,parmIndx)
  580. if verbose > 2:
  581. print 'Parameter %d ADOtype %d, python %s' % (parmIndx,p.Type,type(elem))
  582. if p.Direction in [adParamInput,adParamInputOutput,adParamUnknown]:
  583. tp = type(elem) # python type
  584. if tp in dateconverter.types:
  585. if not defaultParameterList and p.Type in adoDateTimeTypes:
  586. p.Value=dateconverter.COMDate(elem)
  587. else: #probably a string
  588. #Known problem with JET Provider. Date can not be specified as a COM date.
  589. # See for example..http://support.microsoft.com/default.aspx?scid=kb%3ben-us%3b284843
  590. # One workaround is to provide the date as a string in the format 'YYYY-MM-dd'
  591. s = dateconverter.DateObjectToIsoFormatString(elem)
  592. p.Value = s
  593. p.Size = len(s)
  594. elif tp in StringTypes: #v2.1 Jevon
  595. L = len(elem)
  596. if defaultParameterList:
  597. p.Value = elem
  598. else:
  599. if p.Type in adoStringTypes: #v2.2.1 Cole
  600. L = min(L,p.Size) #v2.1 Cole limit data to defined size
  601. p.Value = elem[:L] #v2.1 Jevon & v2.1 Cole
  602. else:
  603. p.Value = elem # dont limit if db column is numeric
  604. if L>0: #v2.1 Cole something does not like p.Size as Zero
  605. p.Size = L #v2.1 Jevon
  606. elif tp == memoryViewType: #v2.1 Cole -- ADO BINARY
  607. p.AppendChunk(elem)
  608. elif isinstance(elem,decimal.Decimal): #v2.2 Cole
  609. s = str(elem)
  610. p.Value = s
  611. p.Size = len(s)
  612. elif isinstance(elem, longType) and onIronPython: # Iron Python Long
  613. s = SystemDecimal(elem) # feature workaround for IPy 2.0
  614. p.Value = s
  615. else:
  616. p.Value=elem
  617. if verbose > 2:
  618. print 'Parameter %d type %d stored as: %s' % (parmIndx,p.Type,repr(p.Value))
  619. parmIndx = -2 # kludge to prevent exception handler picking out one parameter
  620. # ----- the actual SQL is executed here ---
  621. if onIronPython:
  622. ra = Reference[int]()
  623. rs = self.cmd.Execute(ra)
  624. count = ra.Value
  625. else: #pywin32
  626. rs, count = self.cmd.Execute()
  627. # ----- ------------------------------- ---
  628. except Exception, e:
  629. tbk = u'\n--ADODBAPI\n'
  630. if parmIndx >= 0:
  631. tbk += u'-- Trying parameter %d = %s\n' \
  632. %(parmIndx, repr(parameters[parmIndx]))
  633. exc_type,exc_value,exc_traceback = sys.exc_info()
  634. tblist=traceback.format_exception(exc_type,exc_value,exc_traceback,8)
  635. tb=''.join(tblist)
  636. tracebackhistory = tbk + tb + u'-- on command: "%s"\n-- with parameters: %s' \
  637. %(operation,parameters)
  638. self._raiseCursorError(DatabaseError,tracebackhistory)
  639. return
  640. try:
  641. self.rowcount = rs.RecordCount
  642. except:
  643. self.rowcount = count
  644. self._makeDescriptionFromRS(rs)
  645. if isStoredProcedureCall and parameters != None:
  646. return self._returnADOCommandParameters(self.cmd)
  647. def execute(self, operation, parameters=None):
  648. """Prepare and execute a database operation (query or command).
  649. Parameters may be provided as sequence or mapping and will be bound to variables in the operation.
  650. Variables are specified in a database-specific notation
  651. (see the module's paramstyle attribute for details). [5]
  652. A reference to the operation will be retained by the cursor.
  653. If the same operation object is passed in again, then the cursor
  654. can optimize its behavior. This is most effective for algorithms
  655. where the same operation is used, but different parameters are bound to it (many times).
  656. For maximum efficiency when reusing an operation, it is best to use
  657. the setinputsizes() method to specify the parameter types and sizes ahead of time.
  658. It is legal for a parameter to not match the predefined information;
  659. the implementation should compensate, possibly with a loss of efficiency.
  660. The parameters may also be specified as list of tuples to e.g. insert multiple rows in
  661. a single operation, but this kind of usage is depreciated: executemany() should be used instead.
  662. Return values are not defined.
  663. [5] The module will use the __getitem__ method of the parameters object to map either positions
  664. (integers) or names (strings) to parameter values. This allows for both sequences and mappings
  665. to be used as input.
  666. The term "bound" refers to the process of binding an input value to a database execution buffer.
  667. In practical terms, this means that the input value is directly used as a value in the operation.
  668. The client should not be required to "escape" the value so that it can be used -- the value
  669. should be equal to the actual database value.
  670. """
  671. self.messages=[]
  672. self._executeHelper(operation,False,parameters)
  673. def executemany(self, operation, seq_of_parameters):
  674. """Prepare a database operation (query or command) and then execute it against all parameter sequences or mappings found in the sequence seq_of_parameters.
  675. Return values are not defined.
  676. """
  677. self.messages=[]
  678. totrecordcount = 0
  679. canCount=True
  680. for params in seq_of_parameters:
  681. self.execute(operation, params)
  682. if self.rowcount == -1:
  683. canCount=False
  684. elif canCount:
  685. totrecordcount+=self.rowcount
  686. if canCount:
  687. self.rowcount=totrecordcount
  688. else:
  689. self.rowcount=-1
  690. def _fetch(self, rows=None):
  691. """ Fetch rows from the recordset.
  692. rows is None gets all (for fetchall).
  693. """
  694. rs=self.rs
  695. if self.conn == None:
  696. self._raiseCursorError(Error,None)
  697. return
  698. if not rs or rs.State == adStateClosed: #v2.1.1 bkline
  699. self._raiseCursorError(Error,None)
  700. return
  701. else:
  702. if rs.State == adStateClosed or rs.BOF or rs.EOF:
  703. if rows == 1: return None # fetchone can return None
  704. else: return [] # fetchall and fetchmany return empty lists
  705. if rows:
  706. ado_results = self.rs.GetRows(rows)
  707. else:
  708. ado_results = self.rs.GetRows()
  709. d=self.description
  710. returnList=[]
  711. i=0
  712. if onIronPython:
  713. type_codes = [descTuple[1] for descTuple in d]
  714. for j in range(len(ado_results)/len(d)):
  715. L = []
  716. for i in range(len(d)):
  717. L.append(convertVariantToPython(ado_results[i,j],type_codes[i]))
  718. returnList.append(tuple(L))
  719. return tuple(returnList)
  720. else: #pywin32
  721. for descTuple in d:
  722. # Desctuple =(name, type_code, display_size, internal_size, precision, scale, null_ok).
  723. type_code=descTuple[1]
  724. returnList.append([convertVariantToPython(r,type_code) for r in ado_results[i]])
  725. i+=1
  726. return tuple(zip(*returnList))
  727. def fetchone(self):
  728. """ Fetch the next row of a query result set, returning a single sequence,
  729. or None when no more data is available.
  730. An Error (or subclass) exception is raised if the previous call to executeXXX()
  731. did not produce any result set or no call was issued yet.
  732. """
  733. self.messages=[]
  734. ret = self._fetch(1)
  735. if ret: # return record (not list of records)
  736. return ret[0]
  737. else:
  738. return ret # (in case of None)
  739. def fetchmany(self, size=None):
  740. """Fetch the next set of rows of a query result, returning a list of tuples. An empty sequence is returned when no more rows are available.
  741. The number of rows to fetch per call is specified by the parameter.
  742. If it is not given, the cursor's arraysize determines the number of rows to be fetched.
  743. The method should try to fetch as many rows as indicated by the size parameter.
  744. If this is not possible due to the specified number of rows not being available,
  745. fewer rows may be returned.
  746. An Error (or subclass) exception is raised if the previous call to executeXXX()
  747. did not produce any result set or no call was issued yet.
  748. Note there are performance considerations involved with the size parameter.
  749. For optimal performance, it is usually best to use the arraysize attribute.
  750. If the size parameter is used, then it is best for it to retain the same value from
  751. one fetchmany() call to the next.
  752. """
  753. self.messages=[]
  754. if size == None:
  755. size = self.arraysize
  756. return self._fetch(size)
  757. def fetchall(self):
  758. """Fetch all (remaining) rows of a query result, returning them as a sequence of sequences (e.g. a list of tuples).
  759. Note that the cursor's arraysize attribute
  760. can affect the performance of this operation.
  761. An Error (or subclass) exception is raised if the previous call to executeXXX()
  762. did not produce any result set or no call was issued yet.
  763. """
  764. self.messages=[]
  765. return self._fetch()
  766. def nextset(self):
  767. """Make the cursor skip to the next available set, discarding any remaining rows from the current set.
  768. If there are no more sets, the method returns None. Otherwise, it returns a true
  769. value and subsequent calls to the fetch methods will return rows from the next result set.
  770. An Error (or subclass) exception is raised if the previous call to executeXXX()
  771. did not produce any result set or no call was issued yet.
  772. """
  773. self.messages=[]
  774. if not self.conn:
  775. self._raiseCursorError(Error,None)
  776. return
  777. if not self.rs:
  778. self._raiseCursorError(Error,None)
  779. return
  780. else:
  781. if onIronPython:
  782. try:
  783. rs = self.rs.NextRecordset()
  784. except TypeError:
  785. rs = None
  786. except Error, exc:
  787. self._raiseCursorError(NotSupportedError, exc.args)
  788. else: #pywin32
  789. try: #[begin 2.1 ekelund]
  790. rsTuple=self.rs.NextRecordset() #
  791. except pywintypes.com_error, exc: # return appropriate error
  792. self._raiseCursorError(NotSupportedError, exc.args)#[end 2.1 ekelund]
  793. rs=rsTuple[0]
  794. self._makeDescriptionFromRS(rs)
  795. if rs:
  796. return True
  797. return None
  798. def setinputsizes(self,sizes):
  799. pass
  800. def setoutputsize(self, size, column=None):
  801. pass
  802. #Type Objects and Constructors
  803. #Many databases need to have the input in a particular format for binding to an operation's input parameters.
  804. #For example, if an input is destined for a DATE column, then it must be bound to the database in a particular
  805. #string format. Similar problems exist for "Row ID" columns or large binary items (e.g. blobs or RAW columns).
  806. #This presents problems for Python since the parameters to the executeXXX() method are untyped.
  807. #When the database module sees a Python string object, it doesn't know if it should be bound as a simple CHAR
  808. #column, as a raw BINARY item, or as a DATE.
  809. #
  810. #To overcome this problem, a module must provide the constructors defined below to create objects that can
  811. #hold special values. When passed to the cursor methods, the module can then detect the proper type of
  812. #the input parameter and bind it accordingly.
  813. #A Cursor Object's description attribute returns information about each of the result columns of a query.
  814. #The type_code must compare equal to one of Type Objects defined below. Type Objects may be equal to more than
  815. #one type code (e.g. DATETIME could be equal to the type codes for date, time and timestamp columns;
  816. #see the Implementation Hints below for details).
  817. def Date(year,month,day):
  818. "This function constructs an object holding a date value. "
  819. return dateconverter.Date(year,month,day)
  820. def Time(hour,minute,second):
  821. "This function constructs an object holding a time value. "
  822. return dateconverter.Time(hour,minute,second)
  823. def Timestamp(year,month,day,hour,minute,second):
  824. "This function constructs an object holding a time stamp value. "
  825. return dateconverter.Timestamp(year,month,day,hour,minute,second)
  826. def DateFromTicks(ticks):
  827. """This function constructs an object holding a date value from the given ticks value
  828. (number of seconds since the epoch; see the documentation of the standard Python time module for details). """
  829. return Date(*time.gmtime(ticks)[:3])
  830. def TimeFromTicks(ticks):
  831. """This function constructs an object holding a time value from the given ticks value
  832. (number of seconds since the epoch; see the documentation of the standard Python time module for details). """
  833. return Time(*time.gmtime(ticks)[3:6])
  834. def TimestampFromTicks(ticks):
  835. """This function constructs an object holding a time stamp value from the given
  836. ticks value (number of seconds since the epoch;
  837. see the documentation of the standard Python time module for details). """
  838. return Timestamp(*time.gmtime(ticks)[:6])
  839. def Binary(aString):
  840. """This function constructs an object capable of holding a binary (long) string value. """
  841. return makeByteBuffer(aString)
  842. #v2.1 Cole comment out: BinaryType = Binary('a')
  843. #SQL NULL values are represented by the Python None singleton on input and output.
  844. #Note: Usage of Unix ticks for database interfacing can cause troubles because of the limited date range they cover.
  845. def pyTypeToADOType(d):
  846. tp=type(d)
  847. try:
  848. return typeMap[tp]
  849. except KeyError:
  850. if tp in dateconverter.types:
  851. return adDate
  852. if tp == type(decimal.Decimal):
  853. return adDecimal
  854. raise DataError
  855. adCmdText = 1
  856. adCmdStoredProc = 4
  857. adParamInput =0x1 # from enum ParameterDirectionEnum
  858. adParamInputOutput =0x3 # from enum ParameterDirectionEnum
  859. adParamOutput =0x2 # from enum ParameterDirectionEnum
  860. adParamReturnValue =0x4 # from enum ParameterDirectionEnum
  861. adParamUnknown =0x0 # from enum ParameterDirectionEnum
  862. adStateClosed =0
  863. adFldMayBeNull=0x40
  864. adModeShareExclusive=0xc
  865. adXactCommitRetaining= 131072
  866. adXactAbortRetaining = 262144
  867. adArray =0x2000 # from enum DataTypeEnum
  868. adBSTR =0x8 # from enum DataTypeEnum
  869. adBigInt =0x14 # from enum DataTypeEnum
  870. adBinary =0x80 # from enum DataTypeEnum
  871. adBoolean =0xb # from enum DataTypeEnum
  872. adChapter =0x88 # from enum DataTypeEnum
  873. adChar =0x81 # from enum DataTypeEnum
  874. adCurrency =0x6 # from enum DataTypeEnum
  875. adDBDate =0x85 # from enum DataTypeEnum
  876. adDBTime =0x86 # from enum DataTypeEnum
  877. adDBTimeStamp =0x87 # from enum DataTypeEnum
  878. adDate =0x7 # from enum DataTypeEnum
  879. adDecimal =0xe # from enum DataTypeEnum
  880. adDouble =0x5 # from enum DataTypeEnum
  881. adEmpty =0x0 # from enum DataTypeEnum
  882. adError =0xa # from enum DataTypeEnum
  883. adFileTime =0x40 # from enum DataTypeEnum
  884. adGUID =0x48 # from enum DataTypeEnum
  885. adIDispatch =0x9 # from enum DataTypeEnum
  886. adIUnknown =0xd # from enum DataTypeEnum
  887. adInteger =0x3 # from enum DataTypeEnum
  888. adLongVarBinary =0xcd # from enum DataTypeEnum
  889. adLongVarChar =0xc9 # from enum DataTypeEnum
  890. adLongVarWChar =0xcb # from enum DataTypeEnum
  891. adNumeric =0x83 # from enum DataTypeEnum
  892. adPropVariant =0x8a # from enum DataTypeEnum
  893. adSingle =0x4 # from enum DataTypeEnum
  894. adSmallInt =0x2 # from enum DataTypeEnum
  895. adTinyInt =0x10 # from enum DataTypeEnum
  896. adUnsignedBigInt =0x15 # from enum DataTypeEnum
  897. adUnsignedInt =0x13 # from enum DataTypeEnum
  898. adUnsignedSmallInt =0x12 # from enum DataTypeEnum
  899. adUnsignedTinyInt =0x11 # from enum DataTypeEnum
  900. adUserDefined =0x84 # from enum DataTypeEnum
  901. adVarBinary =0xcc # from enum DataTypeEnum
  902. adVarChar =0xc8 # from enum DataTypeEnum
  903. adVarNumeric =0x8b # from enum DataTypeEnum
  904. adVarWChar =0xca # from enum DataTypeEnum
  905. adVariant =0xc # from enum DataTypeEnum
  906. adWChar =0x82 # from enum DataTypeEnum
  907. #ado DataTypeEnum -- copy of above, here in decimal, sorted by value
  908. #adEmpty 0 Specifies no value (DBTYPE_EMPTY).
  909. #adSmallInt 2 Indicates a two-byte signed integer (DBTYPE_I2).
  910. #adInteger 3 Indicates a four-byte signed integer (DBTYPE_I4).
  911. #adSingle 4 Indicates a single-precision floating-point value (DBTYPE_R4).
  912. #adDouble 5 Indicates a double-precision floating-point value (DBTYPE_R8).
  913. #adCurrency 6 Indicates a currency value (DBTYPE_CY). Currency is a fixed-point number with four digits to the right of the decimal point. It is stored in an eight-byte signed integer scaled by 10,000.
  914. #adDate 7 Indicates a date value (DBTYPE_DATE). A date is stored as a double, the whole part of which is the number of days since December 30, 1899, and the fractional part of which is the fraction of a day.
  915. #adBSTR 8 Indicates a null-terminated character string (Unicode) (DBTYPE_BSTR).
  916. #adIDispatch 9 Indicates a pointer to an IDispatch interface on a COM object (DBTYPE_IDISPATCH).
  917. #adError 10 Indicates a 32-bit error code (DBTYPE_ERROR).
  918. #adBoolean 11 Indicates a boolean value (DBTYPE_BOOL).
  919. #adVariant 12 Indicates an Automation Variant (DBTYPE_VARIANT).
  920. #adIUnknown 13 Indicates a pointer to an IUnknown interface on a COM object (DBTYPE_IUNKNOWN).
  921. #adDecimal 14 Indicates an exact numeric value with a fixed precision and scale (DBTYPE_DECIMAL).
  922. #adTinyInt 16 Indicates a one-byte signed integer (DBTYPE_I1).
  923. #adUnsignedTinyInt 17 Indicates a one-byte unsigned integer (DBTYPE_UI1).
  924. #adUnsignedSmallInt 18 Indicates a two-byte unsigned integer (DBTYPE_UI2).
  925. #adUnsignedInt 19 Indicates a four-byte unsigned integer (DBTYPE_UI4).
  926. #adBigInt 20 Indicates an eight-byte signed integer (DBTYPE_I8).
  927. #adUnsignedBigInt 21 Indicates an eight-byte unsigned integer (DBTYPE_UI8).
  928. #adFileTime 64 Indicates a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (DBTYPE_FILETIME).
  929. #adGUID 72 Indicates a globally unique identifier (GUID) (DBTYPE_GUID).
  930. #adBinary 128 Indicates a binary value (DBTYPE_BYTES).
  931. #adChar 129 Indicates a string value (DBTYPE_STR).
  932. #adWChar 130 Indicates a null-terminated Unicode character string (DBTYPE_WSTR).
  933. #adNumeric 131 Indicates an exact numeric value with a fixed precision and scale (DBTYPE_NUMERIC). adUserDefined 132 Indicates a user-defined variable (DBTYPE_UDT).
  934. #adUserDefined 132 Indicates a user-defined variable (DBTYPE_UDT).
  935. #adDBDate 133 Indicates a date value (yyyymmdd) (DBTYPE_DBDATE).
  936. #adDBTime 134 Indicates a time value (hhmmss) (DBTYPE_DBTIME).
  937. #adDBTimeStamp 135 Indicates a date/time stamp (yyyymmddhhmmss plus a fraction in billionths) (DBTYPE_DBTIMESTAMP).
  938. #adChapter 136 Indicates a four-byte chapter value that identifies rows in a child rowset (DBTYPE_HCHAPTER).
  939. #adPropVariant 138 Indicates an Automation PROPVARIANT (DBTYPE_PROP_VARIANT).
  940. #adVarNumeric 139 Indicates a numeric value (Parameter object only).
  941. #adVarChar 200 Indicates a string value (Parameter object only).
  942. #adLongVarChar 201 Indicates a long string value (Parameter object only).
  943. #adVarWChar 202 Indicates a null-terminated Unicode character string (Parameter object only).
  944. #adLongVarWChar 203 Indicates a long null-terminated Unicode string value (Parameter object only).
  945. #adVarBinary 204 Indicates a binary value (Parameter object only).
  946. #adLongVarBinary 205 Indicates a long binary value (Parameter object only).
  947. #adArray (Does not apply to ADOX.) 0x2000 A flag value, always combined with another data type constant, that indicates an array of that other data type.
  948. adoErrors= {
  949. 0xe7b :'adErrBoundToCommand ',
  950. 0xe94 :'adErrCannotComplete ',
  951. 0xea4 :'adErrCantChangeConnection ',
  952. 0xc94 :'adErrCantChangeProvider ',
  953. 0xe8c :'adErrCantConvertvalue ',
  954. 0xe8d :'adErrCantCreate ',
  955. 0xea3 :'adErrCatalogNotSet ',
  956. 0xe8e :'adErrColumnNotOnThisRow ',
  957. 0xd5d :'adErrDataConversion ',
  958. 0xe89 :'adErrDataOverflow ',
  959. 0xe9a :'adErrDelResOutOfScope ',
  960. 0xea6 :'adErrDenyNotSupported ',
  961. 0xea7 :'adErrDenyTypeNotSupported ',
  962. 0xcb3 :'adErrFeatureNotAvailable ',
  963. 0xea5 :'adErrFieldsUpdateFailed ',
  964. 0xc93 :'adErrIllegalOperation ',
  965. 0xcae :'adErrInTransaction ',
  966. 0xe87 :'adErrIntegrityViolation ',
  967. 0xbb9 :'adErrInvalidArgument ',
  968. 0xe7d :'adErrInvalidConnection ',
  969. 0xe7c :'adErrInvalidParamInfo ',
  970. 0xe82 :'adErrInvalidTransaction ',
  971. 0xe91 :'adErrInvalidURL ',
  972. 0xcc1 :'adErrItemNotFound ',
  973. 0xbcd :'adErrNoCurrentRecord ',
  974. 0xe83 :'adErrNotExecuting ',
  975. 0xe7e :'adErrNotReentrant ',
  976. 0xe78 :'adErrObjectClosed ',
  977. 0xd27 :'adErrObjectInCollection ',
  978. 0xd5c :'adErrObjectNotSet ',
  979. 0xe79 :'adErrObjectOpen ',
  980. 0xbba :'adErrOpeningFile ',
  981. 0xe80 :'adErrOperationCancelled ',
  982. 0xe96 :'adErrOutOfSpace ',
  983. 0xe88 :'adErrPermissionDenied ',
  984. 0xe9e :'adErrPropConflicting ',
  985. 0xe9b :'adErrPropInvalidColumn ',
  986. 0xe9c :'adErrPropInvalidOption ',
  987. 0xe9d :'adErrPropInvalidValue ',
  988. 0xe9f :'adErrPropNotAllSettable ',
  989. 0xea0 :'adErrPropNotSet ',
  990. 0xea1 :'adErrPropNotSettable ',
  991. 0xea2 :'adErrPropNotSupported ',
  992. 0xbb8 :'adErrProviderFailed ',
  993. 0xe7a :'adErrProviderNotFound ',
  994. 0xbbb :'adErrReadFile ',
  995. 0xe93 :'adErrResourceExists ',
  996. 0xe92 :'adErrResourceLocked ',
  997. 0xe97 :'adErrResourceOutOfScope ',
  998. 0xe8a :'adErrSchemaViolation ',
  999. 0xe8b :'adErrSignMismatch ',
  1000. 0xe81 :'adErrStillConnecting ',
  1001. 0xe7f :'adErrStillExecuting ',
  1002. 0xe90 :'adErrTreePermissionDenied ',
  1003. 0xe8f :'adErrURLDoesNotExist ',
  1004. 0xe99 :'adErrURLNamedRowDoesNotExist ',
  1005. 0xe98 :'adErrUnavailable ',
  1006. 0xe84 :'adErrUnsafeOperation ',
  1007. 0xe95 :'adErrVolumeNotFound ',
  1008. 0xbbc :'adErrWriteFile '
  1009. }
  1010. class DBAPITypeObject(object):
  1011. def __init__(self,valuesTuple):
  1012. self.values = valuesTuple
  1013. def __eq__(self,other):
  1014. return other in self.values
  1015. adoIntegerTypes=(adInteger,adSmallInt,adTinyInt,adUnsignedInt,
  1016. adUnsignedSmallInt,adUnsignedTinyInt,
  1017. adBoolean,adError) #max 32 bits
  1018. adoRowIdTypes=(adChapter,) #v2.1 Rose
  1019. adoLongTypes=(adBigInt,adFileTime,adUnsignedBigInt)
  1020. adoExactNumericTypes=(adDecimal,adNumeric,adVarNumeric,adCurrency) #v2.1 Cole
  1021. adoApproximateNumericTypes=(adDouble,adSingle) #v2.1 Cole
  1022. adoStringTypes=(adBSTR,adChar,adLongVarChar,adLongVarWChar,
  1023. adVarChar,adVarWChar,adWChar,adGUID)
  1024. adoBinaryTypes=(adBinary,adLongVarBinary,adVarBinary)
  1025. adoDateTimeTypes=(adDBTime, adDBTimeStamp, adDate, adDBDate)
  1026. adoRemainingTypes=(adEmpty,adIDispatch,adIUnknown,
  1027. adPropVariant,adArray,adUserDefined,
  1028. adVariant)
  1029. """This type object is used to describe columns in a database that are string-based (e.g. CHAR). """
  1030. STRING = DBAPITypeObject(adoStringTypes)
  1031. """This type object is used to describe (long) binary columns in a database (e.g. LONG, RAW, BLOBs). """
  1032. BINARY = DBAPITypeObject(adoBinaryTypes)
  1033. """This type object is used to describe numeric columns in a database. """
  1034. NUMBER = DBAPITypeObject(adoIntegerTypes + adoLongTypes + \
  1035. adoExactNumericTypes + adoApproximateNumericTypes)
  1036. """This type object is used to describe date/time columns in a database. """
  1037. DATETIME = DBAPITypeObject(adoDateTimeTypes)
  1038. """This type object is used to describe the "Row ID" column in a database. """
  1039. ROWID = DBAPITypeObject(adoRowIdTypes)
  1040. typeMap= { memoryViewType: adBinary,
  1041. float: adNumeric,
  1042. type(None): adEmpty,
  1043. unicode: adBSTR, # this line will be altered by 2to3 to 'str:'
  1044. bool:adBoolean #v2.1 Cole
  1045. }
  1046. if longType != int: #not Python 3
  1047. typeMap[longType] = adBigInt #works in python 2.x
  1048. typeMap[int] = adInteger
  1049. typeMap[bytes] = adBSTR, # 2.x string type
  1050. else: #python 3.0 integrated integers
  1051. ## Should this differentiote between an int that fits in a long and one that requires 64 bit datatype?
  1052. typeMap[int] = adBigInt
  1053. try: # If mx extensions are installed, use mxDateTime
  1054. import mx.DateTime
  1055. dateconverter=mxDateTimeConverter()
  1056. except: # use datetimelibrary by default
  1057. dateconverter=pythonDateTimeConverter()
  1058. # variant type : function converting variant to Python value
  1059. def variantConvertDate(v):
  1060. return dateconverter.DateObjectFromCOMDate(v)
  1061. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1062. # functions to convert database values to Python objects
  1063. def cvtString(variant): # use to get old action of adodbapi v1 if desired
  1064. if onIronPython:
  1065. try:
  1066. return variant.ToString()
  1067. except:
  1068. pass
  1069. return str(variant)
  1070. def cvtNumeric(variant): #all v2.1 Cole
  1071. if onIronPython:
  1072. try:
  1073. return decimal.Decimal(variant.ToString())
  1074. except:
  1075. pass
  1076. try:
  1077. return decimal.Decimal(variant)
  1078. except (ValueError,TypeError):
  1079. try:
  1080. europeVsUS=str(variant).replace(",",".")
  1081. return decimal.Decimal(europeVsUS)
  1082. except:
  1083. raise
  1084. except:
  1085. raise
  1086. def cvtFloat(variant):
  1087. try:
  1088. return float(variant)
  1089. except (ValueError,TypeError):
  1090. try:
  1091. europeVsUS=str(variant).replace(",",".") #v2.1 Cole
  1092. return float(europeVsUS)
  1093. except:
  1094. raise
  1095. except:
  1096. raise
  1097. def cvtBuffer(variant):
  1098. return makeByteBuffer(variant)
  1099. def cvtUnicode(variant):
  1100. return unicode(variant) # will be altered by 2to3 to 'str(variant)'
  1101. def identity(x): return x
  1102. class VariantConversionMap(dict):
  1103. def __init__(self, aDict):
  1104. for k, v in aDict.items():
  1105. self[k] = v # we must call __setitem__
  1106. def __setitem__(self, adoType, cvtFn):
  1107. "don't make adoType a string :-)"
  1108. try: # user passed us a tuple, set them individually
  1109. for type in adoType:
  1110. dict.__setitem__(self, type, cvtFn)
  1111. except TypeError: # single value
  1112. dict.__setitem__(self, adoType, cvtFn)
  1113. def __getitem__(self, fromType):
  1114. try:
  1115. return dict.__getitem__(self, fromType)
  1116. except KeyError:
  1117. return identity
  1118. def convertVariantToPython(variant, adType):
  1119. if verbose > 3:
  1120. print 'Converting type_code=%s, val=%s'%(adType,repr(variant))
  1121. print 'conversion function=',repr(variantConversions[adType])
  1122. print ' output=%s'%repr(variantConversions[adType](variant))
  1123. if isinstance(variant,DBNull):
  1124. return None
  1125. return variantConversions[adType](variant)
  1126. #initialize variantConversions dictionary used to convert SQL to Python
  1127. variantConversions = VariantConversionMap( {
  1128. adoDateTimeTypes : variantConvertDate,
  1129. adoApproximateNumericTypes: cvtFloat,
  1130. adCurrency: cvtNumeric,
  1131. adoExactNumericTypes: cvtNumeric, # use cvtNumeric to force decimal rather than unicode
  1132. adoLongTypes : long, # will by altered by 2to3 to ': int'
  1133. adoIntegerTypes: int,
  1134. adoRowIdTypes: int,
  1135. adoStringTypes: identity,
  1136. adoBinaryTypes: cvtBuffer,
  1137. adoRemainingTypes: identity })