From 4b2f7e7f6352154e518a0be6c2b0521624f369a5 Mon Sep 17 00:00:00 2001 From: Jacob Quinn Date: Thu, 16 May 2019 23:29:03 -0600 Subject: [PATCH 1/2] Switch from DataStreams to Tables --- src/tables.jl | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 src/tables.jl diff --git a/src/tables.jl b/src/tables.jl new file mode 100644 index 0000000..a3e129a --- /dev/null +++ b/src/tables.jl @@ -0,0 +1,91 @@ +using Tables + +const column_types = Dict( + JDBC_COLTYPE_ARRAY=>Array, + JDBC_COLTYPE_BIGINT=>Int64, + JDBC_COLTYPE_BIT=>Bool, + JDBC_COLTYPE_BOOLEAN=>Bool, + JDBC_COLTYPE_CHAR=>String, + JDBC_COLTYPE_DATE=>Date, + JDBC_COLTYPE_DECIMAL=>Float64, + JDBC_COLTYPE_DOUBLE=>Float64, + JDBC_COLTYPE_FLOAT=>Float32, + JDBC_COLTYPE_INTEGER=>Int32, + JDBC_COLTYPE_LONGNVARCHAR=>String, + JDBC_COLTYPE_LONGVARCHAR=>String, + JDBC_COLTYPE_NCHAR=>String, + JDBC_COLTYPE_NUMERIC=>Float64, + JDBC_COLTYPE_NVARCHAR=>String, + JDBC_COLTYPE_REAL=>Float64, + JDBC_COLTYPE_ROWID=>Int64, + JDBC_COLTYPE_SMALLINT=>Int16, + JDBC_COLTYPE_TIME=>DateTime, + JDBC_COLTYPE_TIMESTAMP=>DateTime, + JDBC_COLTYPE_TINYINT=>Int8, + JDBC_COLTYPE_VARCHAR=>String + ) + + +usedriver(str::AbstractString) = JavaCall.addClassPath(str) + + +struct Source + rs::JResultSet + md::JResultSetMetaData +end +Source(rs::JResultSet) = Source(rs, getMetaData(rs)) +Source(stmt::JStatement, query::AbstractString) = Source(executeQuery(stmt, query)) +Source(rowit::JDBCRowIterator) = Source(rowit.rs) +function Source(csr::Cursor) + if csr.rs == nothing + throw(ArgumentError("A cursor must contain a valid JResultSet to construct a Source.")) + else + Source(csr.rs) + end +end + +# these methods directly access the underlying JResultSet and are used in Schema constructor +function coltype(s::Source, col::Int) + dtype = get(column_types, getColumnType(s.md, col), Any) + if isNullable(s.md, col) == COLUMN_NO_NULLS + dtype + else + Union{dtype, Missing} + end +end +colname(s::Source, col::Int) = getColumnName(s.md, col) +ncols(s::Source) = getColumnCount(s.md) + +coltypes(s::Source) = Type[coltype(s, i) for i ∈ 1:ncols(s)] +colnames(s::Source) = Symbol[colname(s, i) for i ∈ 1:ncols(s)] + +Tables.istable(::Type{<:Source}) = true +Tables.rowaccess(::Type{<:Source}) = true +Tables.rows(s::Source) = s +Tables.schema(s::Source) = Tables.Schema(colnames(s), coltypes(s)) + +Base.IteratorSize(::Type{<:Source}) = Base.SizeUnknown() +Base.eltype(s::Source) = namedtupletype(Tables.schema(s)) +namedtupletype(::Tables.Schema{names, types}) where {names, types} = NamedTuple{names, types} + +# TODO currently jdbc_get_method is very inefficient +pullfield(s::Source, col::Int) = jdbc_get_method(getColumnType(s.md, col))(s.rs, col) + +jdbcconvert(::Type{T}, s, x) where {T} = convert(T, x) +jdbcconvert(::Type{Union{T, Missing}}, s, x) where {T} = wasNull(s.rs) ? missing : convert(T, x) + +function Base.iterate(s::Source, NT::NamedTuple{names, types}=namedtupletype(s)) where {names, types} + isdone(s.rs) && return nothing + return NT(convert(fieldtype(types, i), s, pullfield(s, i)) for i = 1:fieldcount(types)), NT +end + +load(::Type{T}, s::Source) where {T} = Data.close!(Data.stream!(s, T)) +load(::Type{T}, s::Source) where {T} = Tables.materializer(T)(s) +load(::Type{T}, rs::JResultSet) where {T} = load(T, Source(rs)) +load(::Type{T}, stmt::JStatement, query::AbstractString) where {T} = load(T, Source(stmt, query)) +load(::Type{T}, csr::Union{JDBC.Cursor,JDBCRowIterator}) where {T} = load(T, Source(csr)) +function load(::Type{T}, csr::Cursor, q::AbstractString) where T + execute!(csr, q) + load(T, csr) +end + From ac3b1e0542a7a96262b3d6f6f7e85467d6317d75 Mon Sep 17 00:00:00 2001 From: Jacob Quinn Date: Thu, 16 May 2019 23:30:07 -0600 Subject: [PATCH 2/2] Remove old datastreams file --- src/JDBC.jl | 2 +- src/datastreams.jl | 98 ---------------------------------------------- 2 files changed, 1 insertion(+), 99 deletions(-) delete mode 100644 src/datastreams.jl diff --git a/src/JDBC.jl b/src/JDBC.jl index 4fe19b9..15da065 100644 --- a/src/JDBC.jl +++ b/src/JDBC.jl @@ -640,7 +640,7 @@ export getTableMetaData, JDBCRowIterator include("interface.jl") -include("datastreams.jl") +include("tables.jl") end # module diff --git a/src/datastreams.jl b/src/datastreams.jl deleted file mode 100644 index 1a96c86..0000000 --- a/src/datastreams.jl +++ /dev/null @@ -1,98 +0,0 @@ -using DataStreams - -const column_types = Dict( - JDBC_COLTYPE_ARRAY=>Array, - JDBC_COLTYPE_BIGINT=>Int64, - JDBC_COLTYPE_BIT=>Bool, - JDBC_COLTYPE_BOOLEAN=>Bool, - JDBC_COLTYPE_CHAR=>String, - JDBC_COLTYPE_DATE=>Date, - JDBC_COLTYPE_DECIMAL=>Float64, - JDBC_COLTYPE_DOUBLE=>Float64, - JDBC_COLTYPE_FLOAT=>Float32, - JDBC_COLTYPE_INTEGER=>Int32, - JDBC_COLTYPE_LONGNVARCHAR=>String, - JDBC_COLTYPE_LONGVARCHAR=>String, - JDBC_COLTYPE_NCHAR=>String, - JDBC_COLTYPE_NUMERIC=>Float64, - JDBC_COLTYPE_NVARCHAR=>String, - JDBC_COLTYPE_REAL=>Float64, - JDBC_COLTYPE_ROWID=>Int64, - JDBC_COLTYPE_SMALLINT=>Int16, - JDBC_COLTYPE_TIME=>DateTime, - JDBC_COLTYPE_TIMESTAMP=>DateTime, - JDBC_COLTYPE_TINYINT=>Int8, - JDBC_COLTYPE_VARCHAR=>String - ) - - -usedriver(str::AbstractString) = JavaCall.addClassPath(str) - - -struct Source - rs::JResultSet - md::JResultSetMetaData -end -Source(rs::JResultSet) = Source(rs, getMetaData(rs)) -Source(stmt::JStatement, query::AbstractString) = Source(executeQuery(stmt, query)) -Source(rowit::JDBCRowIterator) = Source(rowit.rs) -function Source(csr::Cursor) - if csr.rs == nothing - throw(ArgumentError("A cursor must contain a valid JResultSet to construct a Source.")) - else - Source(csr.rs) - end -end - -# these methods directly access the underlying JResultSet and are used in Schema constructor -function coltype(s::Source, col::Int) - dtype = get(column_types, getColumnType(s.md, col), Any) - if isNullable(s.md, col) == COLUMN_NO_NULLS - dtype - else - Union{dtype, Missing} - end -end -colname(s::Source, col::Int) = getColumnName(s.md, col) -ncols(s::Source) = getColumnCount(s.md) - -coltypes(s::Source) = Type[coltype(s, i) for i ∈ 1:ncols(s)] -colnames(s::Source) = String[colname(s, i) for i ∈ 1:ncols(s)] - -# WARNING: this does not seem to actually work -Data.reset!(s::Source) = beforeFirst!(s.rs) - -Data.isdone(s::Source, row::Int, col::Int) = isdone(s.rs) - -Data.schema(s::Source) = Data.Schema(coltypes(s), colnames(s), missing) - -Data.accesspattern(s::Source) = Data.Sequential - -Data.streamtype(::Type{Source}, ::Type{Data.Field}) = true -Data.streamtype(::Type{Source}, ::Type{Data.Column}) = false - -# TODO currently jdbc_get_method is very inefficient -pullfield(s::Source, col::Int) = jdbc_get_method(getColumnType(s.md, col))(s.rs, col) - -# does not store current row number as a persistent state -function Data.streamfrom(s::Source, ::Type{Data.Field}, ::Type{T}, row::Int, col::Int) where T - convert(T, pullfield(s, col))::T -end -function Data.streamfrom(s::Source, ::Type{Data.Field}, ::Type{Union{T, Missing}}, - row::Int, col::Int) where T - o = pullfield(s, col) - if wasNull(s.rs) - return missing - end - convert(T, o)::T -end - -load(::Type{T}, s::Source) where {T} = Data.close!(Data.stream!(s, T)) -load(::Type{T}, rs::JResultSet) where {T} = load(T, Source(rs)) -load(::Type{T}, stmt::JStatement, query::AbstractString) where {T} = load(T, Source(stmt, query)) -load(::Type{T}, csr::Union{JDBC.Cursor,JDBCRowIterator}) where {T} = load(T, Source(csr)) -function load(::Type{T}, csr::Cursor, q::AbstractString) where T - execute!(csr, q) - load(T, csr) -end -