sqlite_table.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:12k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: sqlite_table.cpp,v $
  4.  * PRODUCTION Revision 1000.1  2004/06/01 19:42:49  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.3
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: sqlite_table.cpp,v 1000.1 2004/06/01 19:42:49 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Authors:  Mike DiCuccio
  35.  *
  36.  * File Description:
  37.  *
  38.  */
  39. #include <ncbi_pch.hpp>
  40. #include <objtools/data_loaders/table/sqlite_table.hpp>
  41. #include <sqlite/sqlite.hpp>
  42. #include <corelib/ncbifile.hpp>
  43. BEGIN_NCBI_SCOPE
  44. USING_SCOPE(objects);
  45. //
  46. // class CSQliteTableIterator is private - no external class can refer to
  47. // this class directly
  48. //
  49. class CSQLiteTableIterator : public ITableIterator
  50. {
  51. public:
  52.     CSQLiteTableIterator(CSQLiteQuery& q)
  53.         : m_Query(&q)
  54.     {
  55.         Next();
  56.     }
  57.     // retrieve the current row's data
  58.     void GetRow(list<string>& data) const
  59.     {
  60.         data = m_ThisRow;
  61.     }
  62.     // advance to the next row
  63.     void Next(void)
  64.     {
  65.         int count = 0;
  66.         const char** data = NULL;
  67.         const char** cols = NULL;
  68.         if ( !m_Query->NextRow(count, data, cols) ) {
  69.             m_Query.Reset();
  70.         }
  71.         m_ThisRow.clear();
  72.         if (data  &&  count) {
  73.             // remember that our data contains the row_idx
  74.             // as the first entry!
  75.             for (int i = 1;  i < count;  ++i) {
  76.                 m_ThisRow.push_back(data[i]);
  77.             }
  78.         }
  79.     }
  80.     // check to see if the current iterator is valid
  81.     bool IsValid(void) const
  82.     {
  83.         return m_Query;
  84.     }
  85. private:
  86.     CRef<CSQLiteQuery> m_Query;
  87.     list<string> m_ThisRow;
  88. };
  89. CSQLiteTable::CSQLiteTable(const string& input_file,
  90.                            const string& temp_file,
  91.                            bool delete_file)
  92.     : m_NumRows(0),
  93.       m_DeleteFile(delete_file),
  94.       m_FileName(input_file),
  95.       m_TmpFileName(temp_file)
  96. {
  97.     //
  98.     // first, see if our temporary file is already a SQLite DB
  99.     //
  100.     CFile file(temp_file);
  101.     if (file.Exists()) {
  102.         try {
  103.             m_Sqlite.Reset(new CSQLite(temp_file, false));
  104.             //
  105.             // retrieve our columns
  106.             //
  107.             CRef<CSQLiteQuery> q
  108.                 (m_Sqlite->Compile("select col, name from TableCols"));
  109.             int count;
  110.             const char** data = NULL;
  111.             const char** cols = NULL;
  112.             while (q.GetPointer()  &&  q->NextRow(count, data, cols)) {
  113.                 string col(data[0]);
  114.                 string str(data[1]);
  115.                 string::size_type pos = 0;
  116.                 while ( (pos = str.find_first_of("'", pos)) != string::npos) {
  117.                     if (pos  &&  str[pos-1] == '\') {
  118.                         str.erase(pos - 1, 1);
  119.                         --pos;
  120.                     }
  121.                     ++pos;
  122.                 }
  123.                 m_Cols.push_back(str);
  124.             }
  125.             return;
  126.         }
  127.         catch (...) {
  128.             // exception thrown on trying to access the data
  129.             // the file isn't valid
  130.             x_CleanUp();
  131.         }
  132.     }
  133.     //
  134.     // oops, not so - must create anew...
  135.     //
  136.     try {
  137.         _TRACE("CSQLiteTable: input = " << input_file
  138.                << " db = " << temp_file);
  139.         string line;
  140.         vector<string> toks;
  141.         m_Sqlite.Reset(new CSQLite(temp_file, delete_file));
  142.         //
  143.         // first, parse the header line
  144.         // this contains the column descriptions
  145.         //
  146.         CNcbiIfstream istr(input_file.c_str());
  147.         int cols = 0;
  148.         while (NcbiGetlineEOL(istr, line)) {
  149.             if (line.empty()  ||  line[0] == '#') {
  150.                 continue;
  151.             }
  152.             NStr::Tokenize(line, "t", m_Cols);
  153.             if (m_Cols.size() == 0) {
  154.                 continue;
  155.             }
  156.             //
  157.             // first readable line is column headers
  158.             // we create two tables - the column header meta-table and
  159.             // the main data table
  160.             //
  161.             // create our schema
  162.             //
  163.             m_Sqlite->Execute("create table TableCols ("
  164.                               "col VARCHAR(32) NOT NULL, "
  165.                               "name VARCHAR(255) NOT NULL, "
  166.                               "desc VARCHAR(255) NULL)");
  167.             int col_idx = 0;
  168.             string schema;
  169.             ITERATE(vector<string>, iter, m_Cols) {
  170.                 string str(*iter);
  171.                 NStr::ToLower(str);
  172.                 string::size_type pos = 0;
  173.                 while ( (pos = str.find_first_of("'", pos)) != string::npos) {
  174.                     str.insert(pos, "\");
  175.                     pos += 2;
  176.                 }
  177.                 m_Sqlite->Execute("insert into TableCols (col, name) "
  178.                                   "values ('col" +
  179.                                   NStr::IntToString(col_idx) + "', '" +
  180.                                   str + "')");
  181.                 if ( !schema.empty() ) {
  182.                     schema += ", ";
  183.                 }
  184.                 schema += "col" + NStr::IntToString(col_idx);
  185.                 ++col_idx;
  186.             }
  187.             schema = "create table TableData (n"
  188.                      "row_idx INTEGER PRIMARY KEY,n" + schema + ");";
  189.             m_Sqlite->Execute(schema);
  190.             cols = m_Cols.size();
  191.             break;
  192.         }
  193.         //
  194.         // now, process the actual data
  195.         //
  196.         m_Sqlite->Execute("begin");
  197.         int row_idx = 0;
  198.         while (NcbiGetlineEOL(istr, line)) {
  199.             if (line.empty()  ||  line[0] == '#') {
  200.                 continue;
  201.             }
  202.             toks.clear();
  203.             NStr::Tokenize(line, "t", toks);
  204.             if (toks.size() == 0) {
  205.                 continue;
  206.             }
  207.             //
  208.             // parse a row
  209.             //
  210.             string schema(NStr::IntToString(row_idx++));
  211.             ITERATE(vector<string>, iter, toks) {
  212.                 string str(*iter);
  213.                 string::size_type pos = 0;
  214.                 while ( (pos = str.find_first_of("'")) != string::npos) {
  215.                     // escape single quotes
  216.                     str.insert(pos, "\");
  217.                     pos += 2;
  218.                 }
  219.                 if ( !schema.empty() ) {
  220.                     schema += ",n";
  221.                 }
  222.                 schema += "'" + *iter + "'";
  223.             }
  224.             for (int i = toks.size(); i < cols;  ++i) {
  225.                 if ( !schema.empty() ) {
  226.                     schema += ",n";
  227.                 }
  228.                 schema += "''";
  229.             }
  230.             schema = "insert into TableData values (n" + schema + ");";
  231.             m_Sqlite->Execute(schema);
  232.         }
  233.         m_Sqlite->Execute("end");
  234.         CRef<CSQLiteQuery> q
  235.             (m_Sqlite->Compile("select count(*) from TableData;"));
  236.         int count = 0;
  237.         const char** data = NULL;
  238.         const char** col_names = NULL;
  239.         if (q->NextRow(count, data, col_names)) {
  240.             m_NumRows = NStr::StringToInt(data[0]);
  241.             LOG_POST(Info << "CSQLiteTable: inserted "
  242.                      << data[0] << " items into local db");
  243.         } else {
  244.             LOG_POST(Info << "compiled query failed");
  245.         }
  246.     }
  247.     catch (...) {
  248.         x_CleanUp();
  249.         throw;
  250.     }
  251. }
  252. CSQLiteTable::~CSQLiteTable()
  253. {
  254.     x_CleanUp();
  255. }
  256. void CSQLiteTable::x_CleanUp()
  257. {
  258.     m_Sqlite.Reset();
  259.     // now, we can (potentially) delete our file
  260.     if (m_DeleteFile) {
  261.         CFile file(m_TmpFileName);
  262.         file.Remove();
  263.     }
  264. }
  265. CSQLite& CSQLiteTable::SetDB(void)
  266. {
  267.     return *m_Sqlite;
  268. }
  269. int CSQLiteTable::GetNumRows(void) const
  270. {
  271.     return m_NumRows;
  272. }
  273. int CSQLiteTable::GetNumCols(void) const
  274. {
  275.     return m_Cols.size();
  276. }
  277. void CSQLiteTable::GetRow(int row, list<string>& data) const
  278. {
  279.     _ASSERT(row >= 0  &&  row < m_NumRows);
  280.     CRef<CSQLiteQuery> q
  281.         (m_Sqlite->Compile("select * from TableData where row_idx = "
  282.                            + NStr::IntToString(row)));
  283.     data.clear();
  284.     if ( !q ) {
  285.         return;
  286.     }
  287.     int count = 0;
  288.     const char** row_data = NULL;
  289.     const char** cols = NULL;
  290.     q->NextRow(count, row_data, cols);
  291.     if ( !row_data ) {
  292.         return;
  293.     }
  294.     for (int i = 1;  i < count;  ++i) {
  295.         data.push_back(row_data[i]);
  296.     }
  297. }
  298. void CSQLiteTable::GetColumnTitle(int col, string& title) const
  299. {
  300.     _ASSERT(col >= 0  && col < m_Cols.size());
  301.     CRef<CSQLiteQuery> q
  302.         (m_Sqlite->Compile("select name from TableCols where col = 'col"
  303.                            + NStr::IntToString(col) + "'"));
  304.     title.erase();
  305.     if ( !q ) {
  306.         return;
  307.     }
  308.     int count = 0;
  309.     const char** row_data = NULL;
  310.     const char** cols = NULL;
  311.     q->NextRow(count, row_data, cols);
  312.     if ( !row_data ) {
  313.         return;
  314.     }
  315.     title = row_data[0];
  316. }
  317. void CSQLiteTable::GetColumnTitles(list<string>& titles) const
  318. {
  319.     CRef<CSQLiteQuery> q
  320.         (m_Sqlite->Compile("select name from TableCols "
  321.                            "where col like 'col%'"));
  322.     titles.clear();
  323.     if ( !q ) {
  324.         return;
  325.     }
  326.     int count = 0;
  327.     const char** row_data = NULL;
  328.     const char** cols = NULL;
  329.     while (q->NextRow(count, row_data, cols)) {
  330.         titles.push_back(row_data[0]);
  331.     }
  332. }
  333. // access an iterator for the entire table
  334. CSQLiteTable::TIterator CSQLiteTable::Begin(void)
  335. {
  336.     return Begin("select * from TableData");
  337. }
  338. // obtain an iterator valid for a given ID
  339. CSQLiteTable::TIterator CSQLiteTable::Begin(const CSeq_id& id)
  340. {
  341.     return Begin();
  342. }
  343. // obtain an iterator valid for a given location
  344. CSQLiteTable::TIterator CSQLiteTable::Begin(const CSeq_loc& id)
  345. {
  346.     return Begin();
  347. }
  348. // obtain an iterator valid for a given SQL query
  349. CSQLiteTable::TIterator CSQLiteTable::Begin(const string& query)
  350. {
  351.     CRef<CSQLiteQuery> q(m_Sqlite->Compile(query));
  352.     if ( !q ) {
  353.         return TIterator();
  354.     }
  355.     return TIterator(new CSQLiteTableIterator(*q));
  356. }
  357. END_NCBI_SCOPE
  358. /*
  359.  * ===========================================================================
  360.  * $Log: sqlite_table.cpp,v $
  361.  * Revision 1000.1  2004/06/01 19:42:49  gouriano
  362.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.3
  363.  *
  364.  * Revision 1.3  2004/05/21 21:42:53  gorelenk
  365.  * Added PCH ncbi_pch.hpp
  366.  *
  367.  * Revision 1.2  2003/10/02 18:21:20  dicuccio
  368.  * Added Unix projects.  Compilation fixes for gcc on Linux
  369.  *
  370.  * Revision 1.1  2003/10/02 17:50:48  dicuccio
  371.  * Initial revision
  372.  *
  373.  * ===========================================================================
  374.  */