Autopsy  4.6.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
SQLiteViewer.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2018 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.contentviewers;
20 
21 import java.awt.BorderLayout;
22 import java.awt.Component;
23 import java.awt.Cursor;
24 import java.io.File;
25 import java.io.IOException;
26 import java.sql.Connection;
27 import java.sql.DriverManager;
28 import java.sql.ResultSet;
29 import java.sql.ResultSetMetaData;
30 import java.sql.SQLException;
31 import java.sql.Statement;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.Collections;
35 import java.util.LinkedHashMap;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Objects;
39 import java.util.TreeMap;
40 import java.util.logging.Level;
41 import javax.swing.JComboBox;
42 import org.openide.util.NbBundle;
43 import org.openide.windows.WindowManager;
50 import org.sleuthkit.datamodel.AbstractFile;
51 import org.sleuthkit.datamodel.SleuthkitCase;
52 import org.sleuthkit.datamodel.TskCoreException;
55 
59 public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
60 
61  private static final long serialVersionUID = 1L;
62  public static final String[] SUPPORTED_MIMETYPES = new String[]{"application/x-sqlite3"};
63  private static final int ROWS_PER_PAGE = 100;
64  private static final Logger logger = Logger.getLogger(FileViewer.class.getName());
65  private final SQLiteTableView selectedTableView = new SQLiteTableView();
66  private AbstractFile sqliteDbFile;
67  private File tmpDbFile;
68  private Connection connection;
69  private int numRows; // num of rows in the selected table
70  private int currPage = 0; // curr page of rows being displayed
71 
75  public SQLiteViewer() {
77  jTableDataPanel.add(selectedTableView, BorderLayout.CENTER);
78  }
79 
85  @SuppressWarnings("unchecked")
86  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
87  private void initComponents() {
88 
89  jHdrPanel = new javax.swing.JPanel();
90  tablesDropdownList = new javax.swing.JComboBox<>();
91  jLabel1 = new javax.swing.JLabel();
92  numEntriesField = new javax.swing.JTextField();
93  jLabel2 = new javax.swing.JLabel();
94  currPageLabel = new javax.swing.JLabel();
95  jLabel3 = new javax.swing.JLabel();
96  numPagesLabel = new javax.swing.JLabel();
97  prevPageButton = new javax.swing.JButton();
98  nextPageButton = new javax.swing.JButton();
99  jTableDataPanel = new javax.swing.JPanel();
100 
101  jHdrPanel.setPreferredSize(new java.awt.Dimension(536, 40));
102 
103  tablesDropdownList.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
104  tablesDropdownList.addActionListener(new java.awt.event.ActionListener() {
105  public void actionPerformed(java.awt.event.ActionEvent evt) {
107  }
108  });
109 
110  org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(SQLiteViewer.class, "SQLiteViewer.jLabel1.text")); // NOI18N
111 
112  numEntriesField.setEditable(false);
113  numEntriesField.setText(org.openide.util.NbBundle.getMessage(SQLiteViewer.class, "SQLiteViewer.numEntriesField.text")); // NOI18N
114  numEntriesField.setBorder(null);
115 
116  org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(SQLiteViewer.class, "SQLiteViewer.jLabel2.text")); // NOI18N
117 
118  org.openide.awt.Mnemonics.setLocalizedText(currPageLabel, org.openide.util.NbBundle.getMessage(SQLiteViewer.class, "SQLiteViewer.currPageLabel.text")); // NOI18N
119 
120  org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(SQLiteViewer.class, "SQLiteViewer.jLabel3.text")); // NOI18N
121 
122  org.openide.awt.Mnemonics.setLocalizedText(numPagesLabel, org.openide.util.NbBundle.getMessage(SQLiteViewer.class, "SQLiteViewer.numPagesLabel.text")); // NOI18N
123 
124  prevPageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"))); // NOI18N
125  org.openide.awt.Mnemonics.setLocalizedText(prevPageButton, org.openide.util.NbBundle.getMessage(SQLiteViewer.class, "SQLiteViewer.prevPageButton.text")); // NOI18N
126  prevPageButton.setBorderPainted(false);
127  prevPageButton.setContentAreaFilled(false);
128  prevPageButton.setDisabledSelectedIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png"))); // NOI18N
129  prevPageButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
130  prevPageButton.setPreferredSize(new java.awt.Dimension(23, 23));
131  prevPageButton.addActionListener(new java.awt.event.ActionListener() {
132  public void actionPerformed(java.awt.event.ActionEvent evt) {
134  }
135  });
136 
137  nextPageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png"))); // NOI18N
138  org.openide.awt.Mnemonics.setLocalizedText(nextPageButton, org.openide.util.NbBundle.getMessage(SQLiteViewer.class, "SQLiteViewer.nextPageButton.text")); // NOI18N
139  nextPageButton.setBorderPainted(false);
140  nextPageButton.setContentAreaFilled(false);
141  nextPageButton.setDisabledSelectedIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png"))); // NOI18N
142  nextPageButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
143  nextPageButton.setPreferredSize(new java.awt.Dimension(23, 23));
144  nextPageButton.addActionListener(new java.awt.event.ActionListener() {
145  public void actionPerformed(java.awt.event.ActionEvent evt) {
147  }
148  });
149 
150  javax.swing.GroupLayout jHdrPanelLayout = new javax.swing.GroupLayout(jHdrPanel);
151  jHdrPanel.setLayout(jHdrPanelLayout);
152  jHdrPanelLayout.setHorizontalGroup(
153  jHdrPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
154  .addGroup(jHdrPanelLayout.createSequentialGroup()
155  .addContainerGap()
156  .addComponent(jLabel1)
157  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
158  .addComponent(tablesDropdownList, javax.swing.GroupLayout.PREFERRED_SIZE, 130, javax.swing.GroupLayout.PREFERRED_SIZE)
159  .addGap(18, 18, 18)
160  .addComponent(numEntriesField, javax.swing.GroupLayout.PREFERRED_SIZE, 71, javax.swing.GroupLayout.PREFERRED_SIZE)
161  .addGap(15, 15, 15)
162  .addComponent(jLabel2)
163  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
164  .addComponent(currPageLabel)
165  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
166  .addComponent(jLabel3)
167  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
168  .addComponent(numPagesLabel)
169  .addGap(18, 18, 18)
170  .addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
171  .addGap(0, 0, 0)
172  .addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
173  .addContainerGap(133, Short.MAX_VALUE))
174  );
175  jHdrPanelLayout.setVerticalGroup(
176  jHdrPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
177  .addGroup(jHdrPanelLayout.createSequentialGroup()
178  .addContainerGap()
179  .addGroup(jHdrPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
180  .addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
181  .addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
182  .addGroup(jHdrPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
183  .addComponent(tablesDropdownList, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
184  .addComponent(jLabel1)
185  .addComponent(numEntriesField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
186  .addComponent(jLabel2)
187  .addComponent(currPageLabel)
188  .addComponent(jLabel3)
189  .addComponent(numPagesLabel)))
190  .addContainerGap())
191  );
192 
193  jTableDataPanel.setLayout(new java.awt.BorderLayout());
194 
195  javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
196  this.setLayout(layout);
197  layout.setHorizontalGroup(
198  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
199  .addComponent(jHdrPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
200  .addComponent(jTableDataPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
201  );
202  layout.setVerticalGroup(
203  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
204  .addGroup(layout.createSequentialGroup()
205  .addComponent(jHdrPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 53, javax.swing.GroupLayout.PREFERRED_SIZE)
206  .addGap(0, 0, 0)
207  .addComponent(jTableDataPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 317, Short.MAX_VALUE))
208  );
209  }// </editor-fold>//GEN-END:initComponents
210 
211  private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed
212  WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
213  currPage++;
214  if (currPage * ROWS_PER_PAGE > numRows) {
215  nextPageButton.setEnabled(false);
216  }
217  currPageLabel.setText(Integer.toString(currPage));
218  prevPageButton.setEnabled(true);
219 
220  // read and display a page of rows
221  String tableName = (String) this.tablesDropdownList.getSelectedItem();
222  readTable(tableName, (currPage - 1) * ROWS_PER_PAGE + 1, ROWS_PER_PAGE);
223  WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
224  }//GEN-LAST:event_nextPageButtonActionPerformed
225 
226  private void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prevPageButtonActionPerformed
227 
228  WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
229  currPage--;
230  if (currPage == 1) {
231  prevPageButton.setEnabled(false);
232  }
233  currPageLabel.setText(Integer.toString(currPage));
234  nextPageButton.setEnabled(true);
235 
236  // read and display a page of rows
237  String tableName = (String) this.tablesDropdownList.getSelectedItem();
238  readTable(tableName, (currPage - 1) * ROWS_PER_PAGE + 1, ROWS_PER_PAGE);
239  WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
240  }//GEN-LAST:event_prevPageButtonActionPerformed
241 
242  private void tablesDropdownListActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tablesDropdownListActionPerformed
243  JComboBox<?> cb = (JComboBox<?>) evt.getSource();
244  String tableName = (String) cb.getSelectedItem();
245  if (null == tableName) {
246  return;
247  }
248  WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
249  selectTable(tableName);
250  WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
251  }//GEN-LAST:event_tablesDropdownListActionPerformed
252 
253 
254  // Variables declaration - do not modify//GEN-BEGIN:variables
255  private javax.swing.JLabel currPageLabel;
256  private javax.swing.JPanel jHdrPanel;
257  private javax.swing.JLabel jLabel1;
258  private javax.swing.JLabel jLabel2;
259  private javax.swing.JLabel jLabel3;
260  private javax.swing.JPanel jTableDataPanel;
261  private javax.swing.JButton nextPageButton;
262  private javax.swing.JTextField numEntriesField;
263  private javax.swing.JLabel numPagesLabel;
264  private javax.swing.JButton prevPageButton;
265  private javax.swing.JComboBox<String> tablesDropdownList;
266  // End of variables declaration//GEN-END:variables
267 
268  @Override
269  public List<String> getSupportedMIMETypes() {
270  return Arrays.asList(SUPPORTED_MIMETYPES);
271  }
272 
273  @Override
274  public void setFile(AbstractFile file) {
275  WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
276  sqliteDbFile = file;
278  WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
279  }
280 
281  @Override
282  public Component getComponent() {
283  return this;
284  }
285 
286  @Override
287  public void resetComponent() {
288  tablesDropdownList.setEnabled(true);
289  tablesDropdownList.removeAllItems();
290  numEntriesField.setText("");
291 
292  // close DB connection to file
293  if (null != connection) {
294  try {
295  connection.close();
296  connection = null;
297  } catch (SQLException ex) {
298  logger.log(Level.SEVERE, "Failed to close DB connection to file.", ex); //NON-NLS
299  }
300  }
301 
302  sqliteDbFile = null;
303  }
304 
308  @NbBundle.Messages({
309  "SQLiteViewer.comboBox.noTableEntry=No tables found",
310  "SQLiteViewer.errorMessage.interrupted=The processing of the file was interrupted.",
311  "SQLiteViewer.errorMessage.noCurrentCase=The case has been closed.",
312  "SQLiteViewer.errorMessage.failedToExtractFile=The file could not be extracted from the data source.",
313  "SQLiteViewer.errorMessage.failedToQueryDatabase=The database tables in the file could not be read.",
314  "SQLiteViewer.errorMessage.failedToinitJDBCDriver=The JDBC driver for SQLite could not be loaded.",
315  "# {0} - exception message", "SQLiteViewer.errorMessage.unexpectedError=An unexpected error occurred:\n{0).",})
316  private void processSQLiteFile() {
317 
318  tablesDropdownList.removeAllItems();
319 
320  // Copy the file to temp folder
321  String tmpDBPathName;
322  try {
323  tmpDBPathName = Case.getOpenCase().getTempDirectory() + File.separator + sqliteDbFile.getName();
324  } catch (NoCurrentCaseException ex) {
325  logger.log(Level.SEVERE, "Current case has been closed", ex); //NON-NLS
326  MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_errorMessage_noCurrentCase());
327  return;
328  }
329 
330  tmpDbFile = new File(tmpDBPathName);
331  if (! tmpDbFile.exists()) {
332  try {
333  ContentUtils.writeToFile(sqliteDbFile, tmpDbFile);
334 
335  // Look for any meta files associated with this DB - WAL, SHM, etc.
336  findAndCopySQLiteMetaFile(sqliteDbFile, sqliteDbFile.getName() + "-wal");
337  findAndCopySQLiteMetaFile(sqliteDbFile, sqliteDbFile.getName() + "-shm");
338  } catch (IOException | NoCurrentCaseException | TskCoreException ex) {
339  logger.log(Level.SEVERE, String.format("Failed to create temp copy of DB file '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
340  MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_errorMessage_failedToExtractFile());
341  return;
342  }
343  }
344 
345  try {
346  // Load the SQLite JDBC driver, if necessary.
347  Class.forName("org.sqlite.JDBC"); //NON-NLS
348  connection = DriverManager.getConnection("jdbc:sqlite:" + tmpDBPathName); //NON-NLS
349 
350  Map<String, String> dbTablesMap = getTables();
351  if (dbTablesMap.isEmpty()) {
352  tablesDropdownList.addItem(Bundle.SQLiteViewer_comboBox_noTableEntry());
353  tablesDropdownList.setEnabled(false);
354  } else {
355  dbTablesMap.keySet().forEach((tableName) -> {
356  tablesDropdownList.addItem(tableName);
357  });
358  }
359  } catch (ClassNotFoundException ex) {
360  logger.log(Level.SEVERE, String.format("Failed to initialize JDBC SQLite '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
361  MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_errorMessage_failedToinitJDBCDriver());
362  } catch (SQLException ex) {
363  logger.log(Level.SEVERE, String.format("Failed to get tables from DB file '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
364  MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_errorMessage_failedToQueryDatabase());
365  }
366  }
367 
375  private void findAndCopySQLiteMetaFile(AbstractFile sqliteFile, String metaFileName) throws NoCurrentCaseException, TskCoreException, IOException {
376  Case openCase = Case.getOpenCase();
377  SleuthkitCase sleuthkitCase = openCase.getSleuthkitCase();
378  Services services = new Services(sleuthkitCase);
379  FileManager fileManager = services.getFileManager();
380  List<AbstractFile> metaFiles = fileManager.findFiles(sqliteFile.getDataSource(), metaFileName, sqliteFile.getParent().getName());
381  if (metaFiles != null) {
382  for (AbstractFile metaFile : metaFiles) {
383  String tmpMetafilePathName = openCase.getTempDirectory() + File.separator + metaFile.getName();
384  File tmpMetafile = new File(tmpMetafilePathName);
385  ContentUtils.writeToFile(metaFile, tmpMetafile);
386  }
387  }
388  }
389 
395  private Map<String, String> getTables() throws SQLException {
396  Map<String, String> dbTablesMap = new TreeMap<>();
397  Statement statement = null;
398  ResultSet resultSet = null;
399  try {
400  statement = connection.createStatement();
401  resultSet = statement.executeQuery(
402  "SELECT name, sql FROM sqlite_master "
403  + " WHERE type= 'table' "
404  + " ORDER BY name;"); //NON-NLS
405  while (resultSet.next()) {
406  String tableName = resultSet.getString("name"); //NON-NLS
407  String tableSQL = resultSet.getString("sql"); //NON-NLS
408  dbTablesMap.put(tableName, tableSQL);
409  }
410  } finally {
411  if (null != resultSet) {
412  resultSet.close();
413  }
414  if (null != statement) {
415  statement.close();
416  }
417  }
418  return dbTablesMap;
419  }
420 
421  @NbBundle.Messages({"# {0} - tableName",
422  "SQLiteViewer.selectTable.errorText=Error getting row count for table: {0}"
423  })
424  private void selectTable(String tableName) {
425 
426  try (Statement statement = connection.createStatement();
427  ResultSet resultSet = statement.executeQuery(
428  "SELECT count (*) as count FROM " + tableName)) { //NON-NLS{
429 
430  numRows = resultSet.getInt("count");
431  numEntriesField.setText(numRows + " entries");
432 
433  currPage = 1;
434  currPageLabel.setText(Integer.toString(currPage));
435  numPagesLabel.setText(Integer.toString((numRows / ROWS_PER_PAGE) + 1));
436 
437  prevPageButton.setEnabled(false);
438 
439  if (numRows > 0) {
440  nextPageButton.setEnabled(((numRows > ROWS_PER_PAGE)));
441  readTable(tableName, (currPage - 1) * ROWS_PER_PAGE + 1, ROWS_PER_PAGE);
442  } else {
443  nextPageButton.setEnabled(false);
444  selectedTableView.setupTable(Collections.emptyList());
445  }
446 
447  } catch (SQLException ex) {
448  logger.log(Level.SEVERE, String.format("Failed to load table %s from DB file '%s' (objId=%d)", tableName, sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
449  MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_selectTable_errorText(tableName));
450  }
451  }
452 
453  @NbBundle.Messages({"# {0} - tableName",
454  "SQLiteViewer.readTable.errorText=Error getting rows for table: {0}"})
455  private void readTable(String tableName, int startRow, int numRowsToRead) {
456 
457  try (
458  Statement statement = connection.createStatement();
459  ResultSet resultSet = statement.executeQuery(
460  "SELECT * FROM " + tableName
461  + " LIMIT " + Integer.toString(numRowsToRead)
462  + " OFFSET " + Integer.toString(startRow - 1))) {
463 
464  ArrayList<Map<String, Object>> rows = resultSetToArrayList(resultSet);
465  if (Objects.nonNull(rows)) {
466  selectedTableView.setupTable(rows);
467  } else {
468  selectedTableView.setupTable(Collections.emptyList());
469  }
470  } catch (SQLException ex) {
471  logger.log(Level.SEVERE, String.format("Failed to read table %s from DB file '%s' (objId=%d)", tableName, sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
472  MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_readTable_errorText(tableName));
473  }
474  }
475 
476  @NbBundle.Messages("SQLiteViewer.BlobNotShown.message=BLOB Data not shown")
477  private ArrayList<Map<String, Object>> resultSetToArrayList(ResultSet rs) throws SQLException {
478  ResultSetMetaData metaData = rs.getMetaData();
479  int columns = metaData.getColumnCount();
480  ArrayList<Map<String, Object>> rowlist = new ArrayList<>();
481  while (rs.next()) {
482  Map<String, Object> row = new LinkedHashMap<>(columns);
483  for (int i = 1; i <= columns; ++i) {
484  if (rs.getObject(i) == null) {
485  row.put(metaData.getColumnName(i), "");
486  } else {
487  if (metaData.getColumnTypeName(i).compareToIgnoreCase("blob") == 0) {
488  row.put(metaData.getColumnName(i), Bundle.SQLiteViewer_BlobNotShown_message());
489  } else {
490  row.put(metaData.getColumnName(i), rs.getObject(i));
491  }
492  }
493  }
494  rowlist.add(row);
495  }
496 
497  return rowlist;
498  }
499 }
ArrayList< Map< String, Object > > resultSetToArrayList(ResultSet rs)
void findAndCopySQLiteMetaFile(AbstractFile sqliteFile, String metaFileName)
void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt)
void tablesDropdownListActionPerformed(java.awt.event.ActionEvent evt)
void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt)
static< T > long writeToFile(Content content, java.io.File outputFile, ProgressHandle progress, Future< T > worker, boolean source)
void readTable(String tableName, int startRow, int numRowsToRead)
javax.swing.JComboBox< String > tablesDropdownList
synchronized List< AbstractFile > findFiles(String fileName)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124

Copyright © 2012-2016 Basis Technology. Generated on: Mon May 7 2018
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.