Permalink
Browse files

meta data is all complete

20080519032209-2f820-22f65b5bd433dd7efddeaaf3487fa8ff7eb95d02.gz
  • Loading branch information...
copiousfreetime authored and git-darcs-import committed May 19, 2008
1 parent ce2bafc commit d5d3b534efe05ce994fdc4fa0c5a0cdef3027b1d
View
@@ -190,6 +190,7 @@ void Init_amalgalite3()
rb_define_method(cAS_Database, "autocommit?", am_sqlite3_database_is_autocommit, 0); /* in amalgalite3_database.c */
rb_define_method(cAS_Database, "register_trace_tap", am_sqlite3_database_register_trace_tap, 1); /* in amalgalite3_database.c */
rb_define_method(cAS_Database, "register_profile_tap", am_sqlite3_database_register_profile_tap, 1); /* in amalgalite3_database.c */
rb_define_method(cAS_Database, "column_metadata", am_sqlite3_database_table_column_metadata, 2); /* in amalgalite3_database.c */
/*
* class Statement
View
@@ -42,6 +42,7 @@ extern VALUE am_sqlite3_database_close(VALUE self);
extern VALUE am_sqlite3_database_open16(VALUE self, VALUE rFilename);
extern VALUE am_sqlite3_database_last_insert_rowid(VALUE self);
extern VALUE am_sqlite3_database_is_autocommit(VALUE self);
extern VALUE am_sqlite3_database_table_column_metadata(VALUE self, VALUE tbl_name, VALUE col_name);
extern VALUE am_sqlite3_database_prepare(VALUE self, VALUE rSQL);
extern VALUE am_sqlite3_database_register_trace_tap(VALUE self, VALUE tap);
View
@@ -323,6 +323,61 @@ VALUE am_sqlite3_database_register_profile_tap(VALUE self, VALUE tap)
return Qnil;
}
/**
* :call-seq:
* datatabase.column_metadata( table_name, column_name) -> Hash
*
* Returns a hash containing the meta information about the column. The
* available keys are:
*
* 'declared_data_type' => the declared data type of the column
* 'collation_sequence_name' => the name of the collation sequence for the column
* 'not_null_constraint' => True if the column has a NOT NULL constraint
* 'primary_key' => True if the column is part of a primary key
* 'auto_increment' => True if the column is AUTO INCREMENT
*
*/
VALUE am_sqlite3_database_table_column_metadata(VALUE self, VALUE tbl_name, VALUE col_name)
{
am_sqlite3 *am_db;
int rc;
/* input */
const char *zDbName = NULL;
const char *zTableName = StringValuePtr( tbl_name );
const char *zColumnName = StringValuePtr( col_name );
/* output */
const char *pzDataType = NULL;
const char *pzCollSeq = NULL;
int pNotNull, pPrimaryKey, pAutoinc;
VALUE rHash = rb_hash_new();
VALUE rStr = Qnil;
Data_Get_Struct(self, am_sqlite3, am_db);
rc = sqlite3_table_column_metadata( am_db->db,
"main" , zTableName, zColumnName,
&pzDataType, &pzCollSeq,
&pNotNull, &pPrimaryKey, &pAutoinc);
if ( SQLITE_OK != rc ) {
rb_raise(eAS_Error, "Failure retrieveing column meta data for table '%s' column '%s' : [SQLITE_ERROR %d] : %s\n",
zTableName, zColumnName, rc, sqlite3_errmsg( am_db-> db ));
}
rStr = ( NULL == pzDataType) ? Qnil : rb_str_new2( pzDataType );
rb_hash_aset( rHash, rb_str_new2("declared_data_type"), rStr );
rStr = ( NULL == pzCollSeq) ? Qnil : rb_str_new2( pzCollSeq );
rb_hash_aset( rHash, rb_str_new2("collation_sequence_name"), rStr );
rb_hash_aset( rHash, rb_str_new2("not_null_constraint"), ( pNotNull ? Qtrue : Qfalse ));
rb_hash_aset( rHash, rb_str_new2("primary_key"), ( pPrimaryKey ? Qtrue : Qfalse ));
rb_hash_aset( rHash, rb_str_new2("auto_increment"), ( pAutoinc ? Qtrue : Qfalse ));
return rHash;
}
/***********************************************************************
* Ruby life cycle methods
@@ -275,10 +275,17 @@ VALUE am_sqlite3_statement_column_value(VALUE self, VALUE v_idx)
{
am_sqlite3_stmt *am_stmt;
int idx = FIX2INT( v_idx );
const char* value;
VALUE returning;
Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
return rb_str_new2( (const char *)sqlite3_column_text( am_stmt->stmt, idx ) );
value = sqlite3_column_text( am_stmt->stmt, idx );
if ( NULL == value ) {
returning = Qnil;
} else {
returning = rb_str_new2( value );
}
return returning;
}
/**
View
@@ -0,0 +1,65 @@
#--
# Copyright (c) 2008 Jeremy Hinegardner
# All rights reserved. See LICENSE and/or COPYING for details.
#++
module Amalgalite
#
# a class representing the meta information about an SQLite column
#
class Column
# the column name
attr_accessor :name
# the table to which this column belongs
attr_accessor :table
# the default value of the column. Nil here means that there is no default
# value
attr_accessor :default_value
# the declared data type of the column in the original sql
attr_accessor :declared_data_type
# the collation sequence name of the column
attr_accessor :collation_sequence_name
# true if the column has a NOT NULL constraint, false otherwise
attr_accessor :not_null_constraint
# true if the column is part of a primary key, false otherwise
attr_accessor :primary_key
# true if the column is AUTO INCREMENT, false otherwise
attr_accessor :auto_increment
#
# Create a column with its name and associated table
#
def initialize( name, table )
@name = name
@table = table
end
def has_default_value?
not default_value.nil?
end
def nullable?
not_null_constraint == false
end
def not_null_constraint?
not_null_constraint
end
def primary_key?
primary_key
end
def auto_increment?
auto_increment
end
end
end
View
@@ -309,6 +309,26 @@ def profile_tap=( tap_obj )
def schema( dbname = "main" )
@schema ||= ::Amalgalite::Schema.new( self, dbname )
end
##
# :call-seq:
# db.reload_schema! -> Schema
#
# By default once the schema is obtained, it is cached. This is here to
# force the schema to be reloaded.
#
def reload_schema!
@schema = nil
schema
end
##
# Run a pragma command against the database
#
# Returns the result set of the pragma
def pragma( cmd )
execute("PRAGMA #{cmd}")
end
end
end
View
@@ -5,7 +5,7 @@
module Amalgalite
#
# abstrace of the meta informationa about 1 Index
# a class representing the meta information about an SQLite index
#
class Index
attr_reader :name
View
@@ -5,6 +5,8 @@
require 'amalgalite/table'
require 'amalgalite/index'
require 'amalgalite/column'
require 'amalgalite/view'
module Amalgalite
#
@@ -15,6 +17,8 @@ class Schema
attr_reader :catalog
attr_reader :schema
attr_reader :tables
attr_reader :views
def initialize( db, catalog = 'main', schema = 'sqlite')
@db = db
@@ -37,15 +41,47 @@ def load_schema!
def load_tables
@tables = {}
@db.execute("SELECT tbl_name, sql FROM sqlite_master WHERE type = 'table'") do |table_info|
table = Amalgalite::Table.new( table_info['name'], table_info['sql'] )
table.columns = @db.pragma "table_info( #{table.name })"
table = Amalgalite::Table.new( table_info['tbl_name'], table_info['sql'] )
table.columns = load_columns( table )
@db.execute("SELECT name, sql FROM sqlite_master WHERE type ='index' and tbl_name = @name") do |idx_info|
table.indexes << Amalgalite::Index.new( idx_info['name'], idx_info['sql'], table )
@db.prepare("SELECT name, sql FROM sqlite_master WHERE type ='index' and tbl_name = @name") do |idx_stmt|
idx_stmt.execute( "@name" => table.name) do |idx_info|
table.indexes << Amalgalite::Index.new( idx_info['name'], idx_info['sql'], table )
end
end
@tables[table.name] = table
end
@tables
end
##
# load all the columns for a particular table
#
def load_columns( table )
cols = {}
@db.execute("PRAGMA table_info(#{table.name})") do |row|
col = Amalgalite::Column.new( row['name'], table )
col.default_value = row['dflt_value']
@db.api.column_metadata( table.name, col.name ).each_pair do |key, value|
col.send("#{key}=", value)
end
cols[col.name] = col
end
cols
end
##
# load all the views for the database
#
def load_views
@views = {}
@db.execute("SELECT name, sql FROM sqlite_master WHERE type = 'view'") do |view_info|
view = Amalgalite::View.new( view_info['name'], view_info['sql'] )
@views[view.name] = view
end
@views
end
end
end
View
@@ -5,17 +5,29 @@
module Amalgalite
#
# abstrace of the meta informationa bout 1 table
# a class representing the meta information about an SQLite table
#
class Table
# the table name
attr_reader :name
# the original sql that was used to create this table
attr_reader :sql
# an array of Index objects holding the meta informationa about the indexes
# on this table
attr_accessor :indexes
# an array of Column objects holding the meta information about the columns
# in this table
attr_accessor :columns
def initialize( name, sql )
@name = name
@sql = sql
@indexes = []
@columns = []
end
end
end
View
@@ -0,0 +1,24 @@
#--
# Copyright (c) 2008 Jeremy Hinegardner
# All rights reserved. See LICENSE and/or COPYING for details.
#++
module Amalgalite
#
# a class representing the meta information about an SQLite view
#
class View
# the table name
attr_reader :name
# the original sql that was used to create this table
attr_reader :sql
def initialize( name, sql )
@name = name
@sql = sql
end
end
end
View
@@ -19,8 +19,28 @@
end
it "loads the schema of a database" do
schema = @iso_db.schema
schema = @iso_db.schema
schema.tables.size.should == 2
end
it "loads the views in the database" do
sql = "CREATE VIEW v1 AS SELECT c.name, c.two_letter, s.name, s.subdivision FROM country AS c JOIN subcountry AS s ON c.two_letter = s.country"
@iso_db.execute( sql )
@iso_db.schema.views.size.should == 1
@iso_db.schema.views["v1"].sql.should == sql
end
it "loads the tables and columns" do
@iso_db.schema.tables.size.should == 2
ct = @iso_db.schema.tables['country']
ct.name.should == "country"
ct.columns.size.should == 3
ct.indexes.size.should == 2
ct.columns['two_letter'].should be_primary_key
ct.columns['name'].should_not be_nullable
ct.columns['name'].should be_not_null_constraint
ct.columns['name'].should_not be_has_default_value
ct.columns['id'].should_not be_auto_increment
end
end
View
@@ -34,6 +34,14 @@
s.dump_profile
s.string.should == "42 : test\ntest[test] => sum: 42, sumsq: 1764, n: 1, mean: 42.000000, stddev: 0.000000, min: 42, max: 42\n"
end
it "has a stdout tap" do
s = ::Amalgalite::Taps::Stdout.new
end
it "has a stderr tap" do
s = ::Amalgalite::Taps::Stderr.new
end
end
describe Amalgalite::ProfileSampler do

0 comments on commit d5d3b53

Please sign in to comment.