File: dbBibSQLite.py

package info (click to toggle)
bibus 1.5.2%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 12,488 kB
  • sloc: python: 30,790; sql: 211; makefile: 158; xml: 10; sh: 3
file content (305 lines) | stat: -rw-r--r-- 11,865 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
# Copyright 2004,2005 Pierre Martineau <pmartino@users.sourceforge.net>
# This file is part of Bibus, a bibliographic database that can
# work together with OpenOffice.org to generate bibliographic indexes.
#
# Bibus is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Bibus is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Bibus; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
#
# Part of the Wizard code has been copied from the example "Simple Wizard" included with
# wxPython

from sqlite3 import Error,IntegrityError,connect,version_info,paramstyle					# python >= 2.5
#
import getpass, os
import dbBibBase
dbBibBase.SUBSTR = 'SUBSTR'
#
import wx
import wx.wizard
import BIB

# Database fields definition
# tables are now defines in files
# pysqlite1_tables.py ; pysqlite2_tables.py
# depending on python-sqlite version
TMPTABLE_REF=""
TABLE_REF=""
# This table maps ref to keys. A ref can be mapped to several keys.
# ref_Id = unique Id of bibref table
# key_id= unique Id of bibrefKey table
# the triplet must be unique
TABLE_LINK=""
# This table describes the tree of keys
# user = user name. To know to which user the key belongs to.
# key_id = unique Id of bibrefKey table
# parent = key_id of parent key. NULL = root
# key_name = key name
TABLE_KEY=""
# This table if for queries storage
TABLE_QUERY=""
# table containing modifications
TABLE_MODIF = ""
# table with links to fulltext files (url)
TABLE_FILE = ""

class dbBib(dbBibBase.dbBib):
	def __init__(self,parent=None):
		dbBibBase.dbBib.__init__(self,parent,paramstyle)
		dbBibBase.Error = Error		# needed in dbBibBase for Error in db connection
		dbBibBase.IntegrityError = IntegrityError	# needed in dbBibBase for Error in db connection
		self.filen = BIB.SQLiteFile
		# the conversion from unicode to str below is because of a bug in python-sqlite
		# that does not accept unicode filenames
		# see http://trac.edgewall.org/changeset/6223
		if type(self.filen) == unicode: self.filen = self.filen.encode('utf-8')
		self.user = BIB.SQLiteUSER
		#
		try:
			global TABLE_REF, TMPTABLE_REF, TABLE_LINK, TABLE_KEY, TABLE_QUERY, TABLE_MODIF, TABLE_FILE
			if version_info < (2,0,0):
				self.dbConnection = connect(self.filen,encoding=BIB.ENCODING)
				from pysqlite1_tables import TABLE_REF, TMPTABLE_REF, TABLE_LINK, TABLE_KEY, TABLE_QUERY, TABLE_MODIF, TABLE_FILE
			else:
				self.dbConnection = connect(self.filen )
				from pysqlite2_tables import TABLE_REF, TMPTABLE_REF, TABLE_LINK, TABLE_KEY, TABLE_QUERY, TABLE_MODIF, TABLE_FILE
			self.dbCursor=self.dbConnection.cursor()
			dbBibBase.TABLE_REF, dbBibBase.TABLE_LINK, dbBibBase.TABLE_KEY, dbBibBase.TABLE_QUERY, dbBibBase.TABLE_MODIF, dbBibBase.TABLE_FILE = \
			TABLE_REF, TABLE_LINK, TABLE_KEY, TABLE_QUERY, TABLE_MODIF, TABLE_FILE
		except Error,errorType:
			self.showError(`errorType.args`)

	def selectDatabase(self,db=BIB.SQLiteFile):
		self.filen=db
		self.user = BIB.SQLiteUSER
		try:
			if self.getGrants() == 'rw':	# we have the grants to temporary table creation
				self.dbCursor.execute("CREATE TEMPORARY TABLE %s %s" % (BIB.TMP_ONLINE,TMPTABLE_REF))
				self.dbCursor.execute("CREATE TEMPORARY TABLE %s %s" % (BIB.TMP_IMPORT,TMPTABLE_REF))
				self.dbConnection.commit()
		except Error,errorType:
		    self.showError(`errorType.args`)


	def selectTable(self,tableref=BIB.DB_TABLE_REF,tablekey=BIB.DB_TABLE_KEY,tablelink=BIB.DB_TABLE_LINK,tablequery=BIB.DB_TABLE_QUERY,tablemodif=BIB.DB_TABLE_MODIF,tablefile=BIB.DB_TABLE_FILE):
		self.tableRef = tableref
		self.tableKey = tablekey
		self.tableLink = tablelink
		self.tableQuery = tablequery
		self.tableModif = tablemodif
		self.tableFile = tablefile

	def getTables(self):
		try:
			self.dbCursor.execute("select name from sqlite_master where type='table'")
			return [table[0] for table in self.dbCursor.fetchall()]
		except Error,errorType:
			self.showError(`errorType.args`)
			return []

	def getFields(self,table):
		"""Return a list of field names"""
		try:
			self.table=table
			self.dbCursor.execute('pragma table_info(%s)' % (self.table))
			self.dbConnection.commit()
			return map(lambda x: x[1],self.dbCursor.fetchall())
		except Error,errorType:
			self.showError(`errorType.args`)

	def get_insert_id(self):
		"""Return the last inserted auto_incremented id"""
		try:
			return self.dbCursor.lastrowid
		except AttributeError:				# for pysqlite-1.1 ?
			return self.dbConnection.db.sqlite_last_insert_rowid()

	def getDbInfo(self,key=''):
		"""Return a tuple that represent the database connection. Here  (file,dbTable).
		For another database it could be a file name or ... something that identify the database + connection"""
		if key == u'Online':
			table = BIB.TMP_ONLINE
		elif key == u'Import':
			table = BIB.TMP_IMPORT
		else:
			table = self.tableRef
		return (self.filen, table)

	def getDbDescription(self):
		"""Return a string that describes the connection in order to put it in the Frame title"""
		return u"%s using SQLite" % self.filen

	def createDatabase(self,db=BIB.SQLiteFile,tableref=BIB.DB_TABLE_REF,tablekey=BIB.DB_TABLE_KEY,tablelink=BIB.DB_TABLE_LINK,tablequery=BIB.DB_TABLE_QUERY,tablemodif=BIB.DB_TABLE_MODIF,tablefile=BIB.DB_TABLE_FILE):
		try:
			self.dbCursor.execute("""create table %s %s""" % (tableref,TABLE_REF))
			self.dbCursor.execute("""create table %s %s""" % (tablekey,TABLE_KEY))
			self.dbCursor.execute("""create table %s %s""" % (tablelink,TABLE_LINK))
			self.dbCursor.execute("""create table %s %s""" % (tablequery,TABLE_QUERY))
			self.dbCursor.execute("""create table %s %s""" % (tablemodif,TABLE_MODIF))
			self.dbCursor.execute("""create table %s %s""" % (tablefile,TABLE_FILE))
			self.dbConnection.commit()
			self.filen=db
			self.tableRef=tableref
			self.tableKey=tablekey
			self.tableLink=tablelink
			self.tableQuery = tablequery
			self.tableModif = tablemodif
			self.tableFile = tablefile
		except Error,errorType:
			#print `errorType.args`
			self.showError(`errorType.args`)

	def duplicateIdentifier(self,e):
		"""Return True if the error correspond to a duplicate Identifier
		e.args = ('column Identifier is not unique',)"""
		return e.args == ('column Identifier is not unique',)

	def getGrants(self):
		"""Return a string
		'rw' if we can read and write to the database file
		'rk' if we can just read the database # r=read db ; k = read keytree
		"""
		if os.access( BIB.SQLiteFile, os.R_OK | os.W_OK ):
			return 'rw'
		else:
			return 'rk'
			
# Database cleanup	
	def clean_tableModif(self):
		self.dbCursor.execute("""DELETE FROM %s WHERE ref_Id IN \
									(SELECT ref_Id FROM %s LEFT JOIN %s ON ref_Id=Id WHERE Id IS NULL)"""
									%(self.tableModif,self.tableModif,self.tableRef))
		self.dbConnection.commit()

	def clean_tableFile(self):
		self.dbCursor.execute("""DELETE FROM %s WHERE ref_Id IN \
									(SELECT ref_Id FROM %s LEFT JOIN %s ON ref_Id=Id WHERE Id IS NULL)"""
									%(self.tableFile,self.tableFile,self.tableRef))
		self.dbConnection.commit()

#----------------------------------------------------------------------
class TitledPage(wx.wizard.WizardPageSimple):
	def __init__(self, parent, title):
		wx.wizard.WizardPageSimple.__init__(self, parent)
		self.sizer = self.__makePageTitle(title)

	def __makePageTitle(self, title):
		sizer = wx.BoxSizer(wx.VERTICAL)
		self.SetSizer(sizer)
		title = wx.StaticText(self, -1, title)
		title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD))
		sizer.Add(title, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
		sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 5)
		return sizer

#----------------------------------------------------------------------

class dbWizard(wx.wizard.Wizard):
	"""This is the Frame that open when Menu connect is selected"""
	def __init__(self,parent):
	# Create the wizard and the pages
		self.ID_wiz = wx.NewId()
		self.parent = parent
		self.db = None
		# save original BIB values
		self.Original_SQLiteUSER = BIB.SQLiteUSER
		self.Original_SQLiteFile = BIB.SQLiteFile
		#
		wx.wizard.Wizard.__init__(self,parent, self.ID_wiz, _("Database choice"))
		self.Show(1)
		page1 = TitledPage(self, _("%s connection parameters")%BIB.DB_TYPE)
		self.page1 = page1
		# page1 Layout
		page1.sizer.Add(wx.StaticText(page1, -1, u""))
		page1.sizer1 = wx.FlexGridSizer(2,2,5,5)
		page1.sizer1.AddGrowableCol(1)
		self.user=wx.TextCtrl(page1,-1,BIB.SQLiteUSER)
		self.filen=wx.TextCtrl(page1,-1,BIB.SQLiteFile)
		self.db_file = wx.Button(page1,-1,_("File name ..."))
		page1.sizer1.Add(wx.StaticText(page1, -1, _("UserName")),wx.ALIGN_CENTER_VERTICAL,wx.ALIGN_RIGHT)
		page1.sizer1.Add(self.user, 0, wx.EXPAND)
		page1.sizer1.Add(self.db_file,0,wx.ALIGN_RIGHT)
		page1.sizer1.Add(self.filen, 0, wx.EXPAND)
		page1.sizer.Add(page1.sizer1, 0, wx.EXPAND)
		self.FitToPage(page1)
		self.Layout()

		wx.wizard.EVT_WIZARD_CANCEL(self, self.ID_wiz, self.OnWizCancel)
		wx.EVT_BUTTON(self, self.db_file.GetId(), self.OnFileChoice)
		wx.wizard.EVT_WIZARD_FINISHED(self, self.ID_wiz, self.OnWizFinished)


	def OnWizFinished(self, evt):
		# we are leaving the wizard by clickink the Finish button
		# we first check that the connection is working then we return the dbBib connection
		# before leaving
		BIB.SQLiteFile = self.filen.GetValue()
		BIB.SQLiteUSER = self.user.GetValue()
		### print 'File check...'
		# TO DO: not only check existence but also check if proper Bibus database
		if not os.path.exists(BIB.SQLiteFile):
			# File does not exist...		
			# we restore original values
			BIB.SQLiteUSER = self.Original_SQLiteUSER
			BIB.SQLiteFile = self.Original_SQLiteFile
			# rollback UI... 
			self.filen.SetValue(self.Original_SQLiteFile)
			self.user.SetValue(self.Original_SQLiteUSER)
			# no db selected
			self.db = None
			return
		# ok, file exists, but TO DO: check if it is a SQLite database (in general)
		# the following part pretends already that it is a SQLite database that is open
		# it just checks if the necessary fields are there
		try:
			if self.db != None: self.db.close()
			self.db = dbBib(self.parent)
			self.db.selectDatabase(BIB.SQLiteFile)
			self.db.tableRef = BIB.DB_TABLE_REF
			self.db.tableKey = BIB.DB_TABLE_KEY
			self.db.tableLink = BIB.DB_TABLE_LINK
			self.db.tableQuery = BIB.DB_TABLE_QUERY
			self.db.tableModif = BIB.DB_TABLE_MODIF
			self.db.tableFile = BIB.DB_TABLE_FILE
			self.db.check_db()	# pop an error if some fields are missing
		except (AttributeError, TypeError):
			# ... some fields are missing... the file is not a Bibus database
			# we restore original values
			BIB.SQLiteUSER = self.Original_SQLiteUSER
			BIB.SQLiteFile = self.Original_SQLiteFile
			# rollback UI... 
			self.filen.SetValue(self.Original_SQLiteFile)
			self.user.SetValue(self.Original_SQLiteUSER)
			# no db selected
			self.db = None

	def OnWizCancel(self, evt):
		# we restore original values
		BIB.SQLiteUSER = self.Original_SQLiteUSER
		BIB.SQLiteFile = self.Original_SQLiteFile
		# no db selected
		self.db = None

	def OnFileChoice(self,event):
		filename = wx.FileSelector(_('SQlite database file'))
		self.filen.SetValue(filename)

	def getDbSelected(self):
		"""Return db. None if no selected db. Clear password for security"""
		BIB.SQLiteUSER = self.user.GetValue()
		BIB.SQLiteFile = self.filen.GetValue()
		if self.db != None and BIB.DB_STARTUP == 0: # we store the current database
			BIB.CONFIG.writeConfig(True)
		return self.db