Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1#!/usr/local/bin/python 

2# encoding: utf-8 

3""" 

4Take a sqlite database file and copy the tables within it to a MySQL database 

5 

6Usage: 

7 sqlite2mysql -s <pathToSettingsFile> <pathToSqliteDB> [<tablePrefix>] 

8 

9Options: 

10 

11 pathToSqliteDB path to the sqlite database file 

12 tablePrefix a string to prefix the table names when copying to mysql database 

13 pathToSettingsFile path to a settings file with logging and database information (yaml file) 

14 

15 -h, --help show this help message 

16 -v, --version show version 

17 -s, --settings the settings file 

18""" 

19from builtins import object 

20import sys 

21import os 

22import sqlite3 as lite 

23os.environ['TERM'] = 'vt100' 

24from fundamentals import tools 

25from fundamentals.mysql import writequery 

26 

27from datetime import datetime, date, time 

28 

29def main(arguments=None): 

30 """ 

31 The main function used when ``yaml_to_database.py`` when installed as a cl tool 

32 """ 

33 

34 # setup the command-line util settings 

35 su = tools( 

36 arguments=arguments, 

37 docString=__doc__, 

38 logLevel="WARNING", 

39 options_first=False, 

40 projectName=False 

41 ) 

42 arguments, settings, log, dbConn = su.setup() 

43 

44 # unpack remaining cl arguments using `exec` to setup the variable names 

45 # automatically 

46 for arg, val in list(arguments.items()): 

47 if arg[0] == "-": 

48 varname = arg.replace("-", "") + "Flag" 

49 else: 

50 varname = arg.replace("<", "").replace(">", "") 

51 if isinstance(val, str): 

52 exec(varname + " = '%s'" % (val,)) 

53 else: 

54 exec(varname + " = %s" % (val,)) 

55 if arg == "--dbConn": 

56 dbConn = val 

57 log.debug('%s = %s' % (varname, val,)) 

58 

59 from fundamentals.mysql import sqlite2mysql 

60 converter = sqlite2mysql( 

61 log=log, 

62 settings=settings, 

63 pathToSqlite=pathToSqliteDB, 

64 tablePrefix=tablePrefix, 

65 dbConn=dbConn 

66 ) 

67 converter.convert_sqlite_to_mysql() 

68 

69 return 

70 

71class sqlite2mysql(object): 

72 """ 

73 *Take a sqlite database file and copy the tables within it to a MySQL database* 

74 

75 **Key Arguments** 

76 

77 - ``log`` -- logger 

78 - ``settings`` -- the settings dictionary 

79 - ``pathToSqlite`` -- path to the sqlite database to transfer into the MySQL database 

80 - ``tablePrefix`` -- a prefix to add to all the tablename when converting to mysql. Default *""* 

81 - ``dbConn`` -- mysql database connection  

82  

83 

84 **Usage** 

85 

86 To setup your logger, settings and database connections, please use the ``fundamentals`` package (`see tutorial here <http://fundamentals.readthedocs.io/en/latest/#tutorial>`_).  

87 

88 To convert and import the content of a sqlite database into MySQL run the following: 

89 

90 .. todo:: 

91 

92 - add a tutorial about ``sqlite2mysql`` to documentation 

93 

94 ```python 

95 from fundamentals.mysql import sqlite2mysql 

96 converter = sqlite2mysql( 

97 log=log, 

98 settings=settings, 

99 pathToSqlite="/path/to/sqlite.db", 

100 tablePrefix="external" 

101 ) 

102 converter.convert_sqlite_to_mysql() 

103 ``` 

104  

105 """ 

106 # Initialisation 

107 

108 def __init__( 

109 self, 

110 log, 

111 pathToSqlite, 

112 tablePrefix="", 

113 settings=False, 

114 dbConn=False 

115 ): 

116 self.log = log 

117 log.debug("instansiating a new 'sqlite2mysql' object") 

118 self.settings = settings 

119 self.pathToSqlite = pathToSqlite 

120 self.tablePrefix = tablePrefix 

121 self.dbConn = dbConn 

122 

123 if not self.tablePrefix: 

124 self.tablePrefix = "" 

125 

126 if len(self.tablePrefix): 

127 self.tablePrefix = self.tablePrefix + "_" 

128 # xt-self-arg-tmpx 

129 

130 return None 

131 

132 def convert_sqlite_to_mysql( 

133 self): 

134 """*copy the contents of the sqlite database into the mysql database* 

135 

136 See class docstring for usage 

137 """ 

138 from fundamentals.renderer import list_of_dictionaries 

139 from fundamentals.mysql import directory_script_runner 

140 self.log.debug('starting the ``convert_sqlite_to_mysql`` method') 

141 

142 con = lite.connect(self.pathToSqlite) 

143 con.row_factory = lite.Row 

144 cur = con.cursor() 

145 

146 # GET ALL TABLE NAMES 

147 cur.execute("SELECT name FROM sqlite_master WHERE type='table';") 

148 tables = cur.fetchall() 

149 

150 createStatements = [] 

151 inserts = [] 

152 for table in tables: 

153 table = table['name'] 

154 if table == "sqlite_sequence": 

155 continue 

156 

157 # CREATE TABLE collection_books (folder_id, fingerprint, primary key(folder_id, fingerprint)); 

158 # GENEREATE THE MYSQL CREATE STATEMENTS FOR EACH TABLE 

159 cur.execute( 

160 "SELECT sql FROM sqlite_master WHERE name = '%(table)s';" % locals()) 

161 createStatement = cur.fetchone() 

162 createStatement = createStatement[0].replace('"', '`') + ";" 

163 if "DEFAULT" not in createStatement: 

164 if "primary key(" in createStatement: 

165 tmp = createStatement.split("primary key(") 

166 tmp[0] = tmp[0].replace( 

167 ",", " varchar(150) DEFAULT NULL,") 

168 createStatement = ("primary key(").join(tmp) 

169 if "primary key," in createStatement: 

170 tmp = createStatement.split("primary key,") 

171 tmp[1] = tmp[1].replace( 

172 ",", " varchar(150) DEFAULT NULL,") 

173 tmp[1] = tmp[1].replace( 

174 ");", " varchar(150) DEFAULT NULL);") 

175 createStatement = ("primary key,").join(tmp) 

176 createStatement = createStatement.replace( 

177 "INTEGER PRIMARY KEY", "INTEGER AUTO_INCREMENT PRIMARY KEY") 

178 createStatement = createStatement.replace( 

179 "AUTOINCREMENT", "AUTO_INCREMENT") 

180 createStatement = createStatement.replace( 

181 "DEFAULT 't'", "DEFAULT '1'") 

182 createStatement = createStatement.replace( 

183 "DEFAULT 'f'", "DEFAULT '0'") 

184 createStatement = createStatement.replace(",'t'", ",'1'") 

185 createStatement = createStatement.replace(",'f'", ",'0'") 

186 if "CREATE TABLE `" in createStatement: 

187 createStatement = createStatement.replace( 

188 "CREATE TABLE `", "CREATE TABLE IF NOT EXISTS `" + self.tablePrefix) 

189 else: 

190 createStatement = createStatement.replace( 

191 "CREATE TABLE ", "CREATE TABLE IF NOT EXISTS " + self.tablePrefix) 

192 if ", primary key(" in createStatement: 

193 createStatement = createStatement.replace(", primary key(", """, 

194`dateCreated` datetime DEFAULT CURRENT_TIMESTAMP, 

195`dateLastModified` datetime DEFAULT CURRENT_TIMESTAMP, 

196`updated` tinyint(4) DEFAULT '0', 

197primary key(""") 

198 else: 

199 createStatement = createStatement.replace(");", """, 

200 `dateCreated` datetime DEFAULT CURRENT_TIMESTAMP, 

201 `dateLastModified` datetime DEFAULT CURRENT_TIMESTAMP, 

202 `updated` tinyint(4) DEFAULT '0'); 

203 """) 

204 createStatement = createStatement.replace( 

205 " text primary key", " varchar(100) primary key") 

206 createStatement = createStatement.replace( 

207 "`EntryText` TEXT NOT NULL,", "`EntryText` TEXT,") 

208 createStatement = createStatement.replace( 

209 "`SelectionText` TEXT NOT NULL", "`SelectionText` TEXT") 

210 createStatement = createStatement.replace( 

211 "`Filename` INTEGER NOT NULL,", "`Filename` TEXT NOT NULL,") 

212 createStatement = createStatement.replace( 

213 "`SessionPartUUID` TEXT NOT NULL UNIQUE,", "`SessionPartUUID` VARCHAR(100) NOT NULL UNIQUE,") 

214 createStatement = createStatement.replace( 

215 "`Name` TEXT PRIMARY KEY NOT NULL", "`Name` VARCHAR(100) PRIMARY KEY NOT NULL") 

216 createStatement = createStatement.replace( 

217 " VARCHAR ", " VARCHAR(100) ") 

218 createStatement = createStatement.replace( 

219 " VARCHAR,", " VARCHAR(100),") 

220 

221 if len(createStatement.lower().split("datecreated")) > 2: 

222 createStatement = createStatement.replace( 

223 "`dateCreated` datetime DEFAULT CURRENT_TIMESTAMP,\n", "") 

224 

225 # GRAB THE DATA TO ADD TO THE MYSQL DATABASE TABLES 

226 cur.execute( 

227 "SELECT * from '%(table)s';" % locals()) 

228 rows = cur.fetchall() 

229 

230 allRows = [] 

231 dateCreated = True 

232 for row in rows: 

233 thisDict = dict(row) 

234 # CHECK FOR DATE-CREATED COLUMN - DON'T WANT TO DUPLICATE 

235 if dateCreated and "datecreated" in str(thisDict.keys()).lower(): 

236 dateCreated = False 

237 allRows.append(thisDict) 

238 

239 # RECURSIVELY CREATE MISSING DIRECTORIES 

240 if not os.path.exists("/tmp/headjack/"): 

241 os.makedirs("/tmp/headjack/") 

242 

243 writequery( 

244 log=self.log, 

245 sqlQuery=createStatement, 

246 dbConn=self.dbConn, 

247 ) 

248 

249 from fundamentals.mysql import insert_list_of_dictionaries_into_database_tables 

250 # USE dbSettings TO ACTIVATE MULTIPROCESSING 

251 insert_list_of_dictionaries_into_database_tables( 

252 dbConn=self.dbConn, 

253 log=self.log, 

254 dictList=allRows, 

255 dbTableName=self.tablePrefix + table, 

256 uniqueKeyList=[], 

257 dateModified=True, 

258 dateCreated=dateCreated, 

259 batchSize=10000, 

260 replace=True, 

261 dbSettings=self.settings["database settings"] 

262 ) 

263 

264 # # DUMP THE DATA INTO A MYSQL DATABASE 

265 # dataSet = list_of_dictionaries( 

266 # log=self.log, 

267 # listOfDictionaries=allRows 

268 # ) 

269 # originalList = dataSet.list 

270 # now = datetime.now() 

271 # now = now.strftime("%Y%m%dt%H%M%S%f.sql") 

272 # mysqlData = dataSet.mysql( 

273 # tableName=self.tablePrefix + table, filepath="/tmp/headjack/" + 

274 # now, createStatement=createStatement) 

275 

276 # directory_script_runner( 

277 # log=self.log, 

278 # pathToScriptDirectory="/tmp/headjack/", 

279 # databaseName=self.settings["database settings"]["db"], 

280 # loginPath=self.settings["database settings"]["loginPath"], 

281 # successRule="delete", 

282 # failureRule="failed" 

283 # ) 

284 

285 con.close() 

286 

287 self.log.debug('completed the ``convert_sqlite_to_mysql`` method') 

288 return None 

289 

290 # use the tab-trigger below for new method 

291 # xt-class-method 

292 

293if __name__ == '__main__': 

294 main()