2005/5/9

     
 

LiteTable.h

artefaktur
// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*- 
//
// Copyright (C) 2000-2005 by Roger Rene Kommer / artefaktur, Kassel, Germany.
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License (LGPL).
// 
// 
// This library 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 
// License ACDK-FreeLicense document enclosed in the distribution
// for more for more details.
// This file is part of the Artefaktur Component Development Kit:
//                         ACDK
// 
// Please refer to
// - http://www.acdk.de
// - http://www.artefaktur.com
// - http://acdk.sourceforge.net
// for more information.
// 
// $Header: /cvsroot/acdk/acdk/acdk_sql_sqlite/src/acdk/sql/sqlite/LiteTable.h,v 1.10 2005/04/13 15:38:05 kommer Exp $
#ifndef acdk_sql_sqlite_LiteTable_h
#define acdk_sql_sqlite_LiteTable_h

#include "Config.h"
#include <acdk.h>
#include <acdk/sql/Statement.h>
#include <acdk/sql/SQLException.h>
#include <acdk/sql/ResultSet.h>
#include <acdk/sql/ResultSetMetaData.h>
#include <acdk/lang/dmi/DmiDelegate.h>
#include <acdk/lang/UnsupportedOperationException.h>

#include "LiteConnection.h"

struct sqlite3;
struct sqlite3_stmt;

namespace acdk {
namespace sql {
namespace sqlite {


#define STR2LITESTR(str) str->convert(CCUtf8)
#define STR2LITESTR16(str) str->convert(CCUcs2)
#define LITESTR2STR(cptr) new String(cptr, CCUtf8 | NormalSST)

/**
  storage types of SQLite
*/
enum LiteColType
{
  SqlLiteInteger = 1,
  SqlLiteFloat = 2,
  SqlLiteText = 3,
  SqlLiteBlob = 4,
  SqlLiteNull = 5

};


ACDK_DECL_CLASS(LiteMemTable);
ACDK_DECL_CLASS(LiteTable);

ACDK_DECL_CLASS(LiteDb);

/**
  thin wrapper to the SQLite3 database
*/
class ACDK_SQL_SQLITE_PUBLIC LiteDb
: extends acdk::lang::Object
{
  ACDK_WITH_METAINFO(LiteDb)
protected:
  foreign sqlite3* _con; 
public:
  static RLiteDb openDb(IN(RString) fileName);
  foreign LiteDb(sqlite3* con);
  //void reset();
  bool isClosed() { return _con != 0; }
  void closeDb();
  /**
    execute a sql command on a LiteDB
    The complete result set will be hold in memory
  */
  RLiteMemTable execDirect(IN(RString) sql);
  /**
    executes a SQL command
  */
  void execute(IN(RString) sql);
  /**
    executes a SQL command an calles the delegate for each record set
    The arguments passed to the delegate are:
    - LiteDb __db
    - all fields as String of one record.
    - The delete should return an int. if the return value is != 0 
      no more records will be fetched.
    See also samples in  acdk_sql_sqlite.
  */
  void execute(IN(RString) sql, IN(acdk::lang::dmi::RDmiDelegate) delegate);
  /**
    execute update, return the number of changes
  */
  int  executeUpdate(IN(RString) cmd);
  /**
    creates a prepared statement
  */
  RLiteTable prepareStatement(IN(RString) sql);
  
  /**
    this creates a function can be used inside an SQL Statement.
    It is similar to stored procedure, but the function itself is 
    not stored within the database, but provided by the application
  */
  void createSqlFunction(IN(RString) function, int args, IN(acdk::lang::dmi::RDmiDelegate) delegate);
  /** 
    internal helper to check calls to the C api 
  */
  int checkResult(int result)
  {
    return checkResult(_con, result);
  }
  /** only call this if a prior call failed */
  void checkLastResult()
  {
    checkLastResult(_con);
  }
  foreign sqlite3* getConPtr() { return _con; }
  /** internal helper to check calls to the C api */
  foreign static int checkResult(sqlite3* con, int result);
  /** internal helper to check calls to the C api */
  foreign static void checkLastResult(sqlite3* con);
  /** sqlite3_changes */
  int changes();
  /** return the version string of the sqlite3 c library */
  static RString getVersion();
  /** internal helper */
  void _checkOpenDb();
};



/**
  Wrapper for the C Api of SQLite.
  Represents a result from a prepared statment
  In most cases this class will not be used in user code
  Different to JDBC, internal indeces for columns starts with 0
*/
class ACDK_SQL_SQLITE_PUBLIC LiteTable
: extends acdk::lang::Object
, implements acdk::util::Iterator
{
  ACDK_WITH_METAINFO(LiteTable)
public:
  RLiteDb _db;
  foreign sqlite3_stmt* _stm;
  int _currow;
  bool _rowDelivered;
  bool _hasRow;
  /** how many rows -1 means doesn't know */
  int _rowCount;
  foreign LiteTable(IN(RLiteDb) db, sqlite3_stmt* stm);
  foreign ~LiteTable();

  /** 
    for Iterator interface 
  */
  bool hasNext();
  /** 
    for Iterator interface
    @return this
  */
  acdk::lang::Object next();
  /** 
    for Iterator interface
    return this
  */
  virtual acdk::lang::Object element() { return this; }
  /**
    will throw UnsupportedOperationException
  */
  virtual void remove();
  bool getNext();
  void clearParameters();
  RLiteDb getDb() { return _db; }
  /** current row */
  int curRow() { return _currow; }
  RString getColName(int col);
  void reset();
  int colCount();
  int getColumnByName(IN(RString) name);
  bool getBoolean(int col);
  byte getByte(int col);
  short getShort(int col);
  int getInt(int col);
  jlong getLong(int col);
  float getFloat(int col);
  double getDouble(int col);
  RString getString(int col);
  RFlexByteBuffer getBlob(int col);
  /**
    -1 before first
    0 first
    1 - n absolute
    -2 last
    -3 after last
  */
  bool seek(int rowCount);
  /**
    returns update to last row index
  */
  int seekEnd();
  /**
    returns one of LiteColType
  */
  int getLiteType(int col);
  int getSqlType(int col);
  RString getSQLTypeName(int col);
  RString getColumnClassName(int col);

  /** bind index starts with 1 */
  void bindInt(int col, int val);
  void bindDouble(int col, double val);
  void bindLong(int col, jlong val);
  void bindText(int col, IN(RString) value);
  void bindNull(int col);
  void bindBlob(int col, IN(RReadByteBuffer) buffer);
  /** for Prepared statements */
  int getParameterCount();
  RString getParameterName(int col);
  int getParamterIndexByName(IN(RString) name);
  void checkLastResult()
  {
    LiteDb::checkLastResult(_db->getConPtr());
  }
  int checkResult(int res)
  {
    return LiteDb::checkResult(_db->getConPtr(), res);
  }
};

ACDK_DECL_CLASS(LiteMemTable);

/**
  Different to LiteTable LiteMemTable reads
  the complete result set from a query into memory
  All fields of a record will represented by a string
*/
class ACDK_SQL_SQLITE_PUBLIC LiteMemTable
: extends acdk::lang::Object
{
  ACDK_WITH_METAINFO(LiteMemTable)
protected:
  foreign char **_table;
  int _cols;
  int _rows;
public:
  foreign LiteMemTable(char** table, int cols, int rows)
    : _table(table)
    , _cols(cols)
    , _rows(rows)
  {
  }
  foreign ~LiteMemTable();
  int columnCount() { return _cols; }
  int rowCount() { return _rows; }
  /**
    return the names of the columns 
  */
  RStringArray getColumnNames();
  /** idx starts with 1 */
  RString getColumnName(int col) 
  {
    col = _checkColIdx(col);
    return LITESTR2STR(_table[col]);
  }
  /** row starts with 0 and row starts with 1 */
  RString getField(int row, int col)
  {
    col = _checkColIdx(col);
    row = _checkRowIdx(row);
    return LITESTR2STR(_table[(row * _cols) + col]);
  }
  /** 
    return the maximum needed characters need to display all rows of a col 
    This also includes the column names
  */
  int getMaxColWidth(int col);
  RStringArray getRow(int row)
  {
    row = _checkRowIdx(row);
    RStringArray ra = new StringArray(_cols);
    for (int i = 0; i < _cols; ++i)
      ra[i] = LITESTR2STR(_table[(row * _cols) + i]);
    return ra;
  }
  /**
    returns LiteMemTableIterator
  */
  acdk::util::RIterator iterator();
  /**
    prints a table as ascii:
    <pre>
intcol|stringcol
-----------------
1     |first    
2     |second   
3     |third    
</pre>
*/
  void printTable(IN(acdk::io::RPrintWriter) out);
protected:
  foreign int _checkColIdx(int idx)
  {
    if (idx < 0  || idx > _cols)
      THROW1(SQLException, SBSTR("No column at index: " << idx));
    return idx - 1;
  }
  foreign int _checkRowIdx(int idx)
  {
    if (idx < 0 || idx > _rows)
      THROW1(SQLException, SBSTR("No row at index: " << idx));
    return idx + 1;
  }
};

ACDK_DECL_CLASS(LiteMemTableIterator);

/**
  Iterator adapter for a LiteMemTable
*/
class ACDK_SQL_SQLITE_PUBLIC LiteMemTableIterator
: extends acdk::lang::Object
, implements acdk::util::Iterator
{
  ACDK_WITH_METAINFO(LiteMemTableIterator)
protected:
  RLiteMemTable _table;
  int _row;
public:
  LiteMemTableIterator(IN(RLiteMemTable) table)
  : _table(table)
  , _row(-1)
  {
  }

  RString getColumnName(int col) 
  {
    return _table->getColumnName(col); 
  }
  RString getField(int col) 
  {
    return _table->getField(_row, col);
  }
  /**
    returns an iterator to a string array containing the fields of current row
  */
  acdk::util::RIterator iterator() 
  {
    return _table->getRow(_row)->iterator();
  }
  virtual bool hasNext()
  {
    if (_table->rowCount() == _row + 1)
      return false;
    return true;
  }
  /** 
    @return this
  */
  virtual acdk::lang::Object next()
  {
    ++_row;
    return this;
  }
  virtual acdk::lang::Object element()
  {
    return this;
  }
  virtual void remove() 
  {
    THROW1(UnsupportedOperationException, "LiteMemTableIterator::remove()");
  }

};

inline
acdk::util::RIterator 
LiteMemTable::iterator()
{
  return new LiteMemTableIterator(this);
}




} // sqlite
} // sql 
} // acdk
#endif //acdk_sql_sqlite_LiteTable_h