Skip to content

Commit

Permalink
Attempt native library version detection.
Browse files Browse the repository at this point in the history
Added to mysql and Pg for testing + minor cleanups.
Will be extended but now closes #60.
  • Loading branch information
salortiz committed Apr 7, 2016
1 parent aaa1851 commit 9bc4191
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 61 deletions.
10 changes: 5 additions & 5 deletions lib/DBDish/Pg.pm6
Expand Up @@ -62,21 +62,21 @@ sub quote-and-escape($s) {
}

#------------------ methods to be called from DBIish ------------------
method connect(:database(:$dbname), :$RaiseError, *%params) {
method connect(:database(:$dbname), *%params) {

%params.push((:$dbname));
%params.push((:$dbname)) with $dbname;
my @connection_parameters = gather for %params.kv -> $key, $value {
# Internal parameter, not for PostgreSQL usage.
next if $key ~~ / <-lower> /;
take "$key={quote-and-escape $value}" if $value.defined;
take "$key={quote-and-escape $value}";
}
my $pg_conn = PGconn.new(~@connection_parameters);
my $status = $pg_conn.PQstatus;
if $status == CONNECTION_OK {
DBDish::Pg::Connection.new(:$pg_conn, :$RaiseError, :parent(self), |%params);
DBDish::Pg::Connection.new(:$pg_conn, :parent(self), |%params);
}
else {
self!conn-error: :code($status) :$RaiseError :errstr($pg_conn.PQerrorMessage);
self!conn-error: :code($status) :errstr($pg_conn.PQerrorMessage);
}
}

Expand Down
27 changes: 5 additions & 22 deletions lib/DBDish/Pg/Native.pm6
@@ -1,13 +1,10 @@
use v6;

unit module DBDish::Pg::Native;
use NativeCall :ALL;
use nqp;
use NativeLibs :ALL;
use NativeHelpers::Blob;

sub MyLibName {
%*ENV<DBIISH_PG_LIB> || guess_library_name(('pq', v5));
}
constant LIB = &MyLibName;
constant LIB = NativeLibs::Searcher.at-runtime('pq', 'PQstatus', 5);

#------------ My Visible Types

Expand Down Expand Up @@ -38,20 +35,6 @@ class PGresult is export is repr('CPointer') {
sub PQgetvalue(PGresult, int32, int32 --> Pointer) is native(LIB) { * }
sub PQgetlength(PGresult, int32, int32 --> int32) is native(LIB) { * }
sub PQfformat(PGresult, int32 --> int32) is native(LIB) { * }
sub buf-from-pointer(Pointer \ptr, int :$elems!, Blob:U :$type = Buf) {
# Stolen from NativeHelpers::Blob ;-)
my sub memcpy(Blob:D $dest, Pointer $src, size_t $size)
returns Pointer is native() { * };
my \t = ptr.of ~~ void ?? $type.of !! ptr.of;
my $b = (t === uint8) ?? Buf !! Buf.^parameterize(t);
with ptr {
my \b = $b.new;
nqp::setelems(b, $elems);
memcpy(b, ptr, $elems * nativesizeof(t));
$b = b;
}
$b;
}

my \ptr = PQgetvalue(self, $row, $col);
given PQfformat(self, $col) {
Expand All @@ -65,7 +48,7 @@ class PGresult is export is repr('CPointer') {
my \ptr = PQunescapeBytea($str, my size_t $elems);
LEAVE { PQfreemem(ptr) if ptr }
with ptr {
buf-from-pointer(ptr, :$elems, :type($t))
blob-from-pointer(ptr, :$elems, :type($t))
} else { die "Can't allocate memory!" };
}
default { $t($str) } # Cast
Expand All @@ -77,7 +60,7 @@ class PGresult is export is repr('CPointer') {
given $t {
when Str { nativecast(Str, ptr) }
when Blob {
buf-from-pointer(ptr, :elems($size));
blob-from-pointer(ptr, :elems($size));
}
}
}
Expand Down
27 changes: 10 additions & 17 deletions lib/DBDish/Pg/StatementHandle.pm6
Expand Up @@ -48,8 +48,9 @@ method execute(*@params) {
my @param_values := ParamArray.new;
for @params.kv -> $k, $v {
if $v.defined {
@param_values[$k] = (@!param_type[$k] ~~ Buf)
@param_values[$k] = @!param_type[$k] ~~ Buf
?? $!pg_conn.escapeBytea(($v ~~ Buf) ?? $v !! ~$v.encode)
!! @!param_type[$k] ~~ Array ?? self.pg-array-str($v)
!! ~$v;
} else { @param_values[$k] = Str }
}
Expand Down Expand Up @@ -104,15 +105,9 @@ my grammar PgArrayGrammar {
};

sub _to-type($value, Mu:U $type) {
if $value.defined {
given $type {
when 'Str' { ~$value } # String;
when 'Num' { Num($value) } # SQL Floating point
when 'Rat' { Rat($value) } # SQL Numeric
default { Int($value) } # Must be
}
}
else {
with $value {
$type($value);
} else {
$value;
}
}
Expand Down Expand Up @@ -146,15 +141,13 @@ sub _pg-to-array(Str $text, Mu:U $type) {
method pg-array-str(@data) {
my @tmp;
for @data -> $c {
if $c ~~ Array {
if $c ~~ Array {
@tmp.push(self.pg-array-str($c));
} elsif $c ~~ Numeric {
@tmp.push($c);
} else {
if $c ~~ Numeric {
@tmp.push($c);
} else {
my $t = $c.subst('"', '\\"');
@tmp.push('"'~$t~'"');
}
my $t = $c.subst('"', '\\"');
@tmp.push('"'~$t~'"');
}
}
'{' ~ @tmp.join(',') ~ '}';
Expand Down
10 changes: 3 additions & 7 deletions lib/DBDish/mysql.pm6
Expand Up @@ -7,7 +7,7 @@ use DBDish::mysql::Native;
need DBDish::mysql::Connection;

#------------------ methods to be called from DBIish ------------------
method connect(:$RaiseError, *%params ) {
method connect(*%params ) {
my $connection;
my $mysql_client = MYSQL.mysql_init;
my $errstr = $mysql_client.mysql_error;
Expand All @@ -26,15 +26,11 @@ method connect(:$RaiseError, *%params ) {
unless $errstr = $mysql_client.mysql_error {
$mysql_client.mysql_set_character_set('utf8'); # A sane default
$connection = DBDish::mysql::Connection.new(
:$mysql_client, :$RaiseError, :parent(self), |%params,
:$mysql_client, :parent(self), |%params,
);
}
}
if $errstr {
self!conn-error :$errstr, :$RaiseError;
} else {
$connection;
}
$errstr ?? self!conn-error(:$errstr) !! $connection;
}

=begin pod
Expand Down
11 changes: 4 additions & 7 deletions lib/DBDish/mysql/Native.pm6
@@ -1,13 +1,10 @@
use v6;

unit module DBDish::mysql::Native;
use NativeCall :ALL;
use NativeLibs :ALL;
use NativeHelpers::Blob;

sub MyLibName {
%*ENV<DBIISH_MYSQL_LIB> || guess_library_name(('mysqlclient', v18));
}
constant LIB = &MyLibName;
constant LIB = NativeLibs::Searcher.at-runtime('mysqlclient', 'mysql_init', 16..20);

#From mysql_com.h
enum mysql-field-type is export (
Expand Down Expand Up @@ -70,8 +67,8 @@ class MYSQL_RES is repr('CPointer') { ... }

# Current rakudo don't allow set a Pointer in a CStruct based class.
# so we use an 'intprt'
constant intptr is export = nativesizeof(Pointer) == 8 ?? uint64 !! uint32;
constant ptrsize_t is export = nativesizeof(intptr);
constant ptrsize is export = nativesizeof(Pointer);
constant intptr is export = ptrsize == 8 ?? uint64 !! uint32;
class MYSQL_BIND is repr('CStruct') is export {
#has Pointer[ulong] $!length is rw;
has intptr $.length is rw;
Expand Down
6 changes: 3 additions & 3 deletions lib/DBDish/mysql/StatementHandle.pm6
Expand Up @@ -55,7 +55,7 @@ submethod BUILD(:$!mysql_client!, :$!parent!, :$!stmt = MYSQL_STMT,
my $lb = BPointer(
$!in-lengths = blob-allocate(Buf[intptr], $pc)
).Int;
$!par-binds[$_].length = $lb + $_ * ptrsize_t for ^$pc;
$!par-binds[$_].length = $lb + $_ * ptrsize for ^$pc;
}
if ($!field_count = .mysql_stmt_field_count) && .mysql_stmt_result_metadata -> $res {
$!binds = LinearArray[MYSQL_BIND].new($!field_count);
Expand All @@ -67,8 +67,8 @@ submethod BUILD(:$!mysql_client!, :$!parent!, :$!stmt = MYSQL_STMT,
if .buffer_length = $!out-lengths[$col] {
@!out-bufs[$col] = blob-allocate(Buf, $!out-lengths[$col]);
.buffer = BPointer(@!out-bufs[$col]).Int;
.length = $lb + $col * ptrsize_t;
.is_null = $nb + $col * ptrsize_t;
.length = $lb + $col * ptrsize;
.is_null = $nb + $col * ptrsize;
.buffer_type = @!column-type[$col] ~~ Blob
?? MYSQL_TYPE_BLOB !! MYSQL_TYPE_STRING;
} else {
Expand Down
33 changes: 33 additions & 0 deletions lib/NativeLibs.pm6
@@ -0,0 +1,33 @@
use v6;

unit module NativeLibs:auth<sortiz>:ver<0.0.1>;
use NativeCall :ALL;

class Searcher {
method !test($try, $wks) {
(try cglobal($try, $wks, Pointer)) ~~ Pointer ?? $try !! Nil
}
method search(Str $libname, Str $wks, *@vers) {
my $wlibname;
for @vers {
my $ver = $_.defined ?? Version.new($_) !! Version;
$wlibname = $_ and last with self!test:
guess_library_name(($libname, $ver)), $wks;
}
$wlibname //= self!test: guess_library_name($libname), $wks unless @vers;
$wlibname;
}
method at-runtime($libname, $wks, *@vers) {
-> {
with self.search($libname, $wks, |@vers) {
$_
} else {
die "Cannot locate native library '$libname'";
}
}
}
}
# Reexport all NativeCall
CHECK for NativeCall::EXPORT::.keys {
UNIT::EXPORT::{$_} := NativeCall::EXPORT::{$_};
}
13 changes: 13 additions & 0 deletions t/03-lib-util.t
@@ -0,0 +1,13 @@
use v6;
use Test;

plan 5;

use-ok 'NativeLibs';
ok (my \Util = ::('NativeLibs::Searcher')) !~~ Failure, 'Class Searcher exists';
my $sub = Util.at-runtime('mysqlclient', 'mysql_init', 16..20);
does-ok $sub, Callable;
my $lib;
is $lib = $sub.(), "libmysqlclient.so.18", "Indeed $lib";
ok $lib = Util.search('pq', 'PQstatus', 5), "Postgres is $lib";

0 comments on commit 9bc4191

Please sign in to comment.