Postgres

4 views
Skip to first unread message

Yariv Sadan

unread,
Jan 5, 2007, 1:16:03 PM1/5/07
to erl...@googlegroups.com
Hi,

A couple of people have expressed interest in doing this, but is
anybody actively working on a Postgres adapter for ErlyDB? (I have
recently grown more interested in Postgres due to 2-phase commits and
better multi-cpu utilization than MySQL.)

Regards,
Yariv

Bob Ippolito

unread,
Jan 5, 2007, 1:20:25 PM1/5/07
to erl...@googlegroups.com

I'm not currently working on any PostgreSQL adapter.. but the lack of
one is the primary reason I haven't tried out erlyweb. After several
bad experiences with MySQL, I'm no longer interested in writing new
software that has anything to do with it. I've also grown quite used
to optimizing PostgreSQL and its type system.

FWIW, PostgreSQL also solves your "licensing issue" with the repository.

-bob

Yariv Sadan

unread,
Jan 5, 2007, 1:28:19 PM1/5/07
to erl...@googlegroups.com
I know of 2 Erlang Postgres drivers, one from jungerl, and one from
Erlang Consulting, and neither is released under the MIT license, so I
think the repository issue will be the same with Postgres.

I was initially interested in MySQL because of the built-in clustering
and replication features, which Postgres only has as add-ons of
varying quality. However, with 2 phase commits, you can (relatively)
easily add synchronous replication logic into the driver's connection
pool manager.

Yariv

Bob Ippolito

unread,
Jan 5, 2007, 1:35:11 PM1/5/07
to erl...@googlegroups.com
Well, there's no inherent reason that PostgreSQL should have a
licensing issue. MySQL licenses the protocol and client libraries in
such a way that you can't really build any MySQL driver with a MIT
license.

I have no idea what the quality/status is of any Erlang PostgreSQL
driver.. I do all of my DB stuff with Python and send it to Erlang
over HTTP (the results aren't very volatile).

-bob

Yariv Sadan

unread,
Jan 5, 2007, 8:31:02 PM1/5/07
to erl...@googlegroups.com
The license problem I'm having is that the MySQL driver ErlyDB uses is
based on a codebase that was originally developed by YXA, who released
it under the BSD license. I modified this codebase substantially and
released my modifications as a fork of the original codebase, but I
don't have the freedom to change the BSD licensing. This is why Google
Code may object to my including the MySQL code in the same repository
as ErlyWeb, which I released under the MIT license.

Having said that, I didn't notice anything in the Google Code terms of
service that explicitly forbids including libraries that have
different licenses in a project's repository, so maybe I can bring
the MySQL driver code into the ErlyWeb repository without upsetting
Google too much...

Brian Olsen

unread,
Jan 7, 2007, 1:49:40 PM1/7/07
to erlyweb

Yariv Sadan wrote:
> The license problem I'm having is that the MySQL driver ErlyDB uses is
> based on a codebase that was originally developed by YXA, who released
> it under the BSD license. I modified this codebase substantially and
> released my modifications as a fork of the original codebase, but I
> don't have the freedom to change the BSD licensing. This is why Google
> Code may object to my including the MySQL code in the same repository
> as ErlyWeb, which I released under the MIT license.
>
> Having said that, I didn't notice anything in the Google Code terms of
> service that explicitly forbids including libraries that have
> different licenses in a project's repository, so maybe I can bring
> the MySQL driver code into the ErlyWeb repository without upsetting
> Google too much...

I started work on an adapter using the driver from Erlang Consulting. I
have not looked at it in a few days because of certain other situations
have come up, but I plan to continue hacking on it when I get a chance.

Yariv Sadan

unread,
Jan 7, 2007, 9:59:13 PM1/7/07
to erl...@googlegroups.com
cool... if you want to throw some ideas around about how to implement
it, let me know. I've read this driver's code, and my hunch is that
the best approach would be to reuse the mysql dispatcher code (it's
already quite generic) and glue the only Postgres protocol logic into
the dispatcher's backend. This would involve renaming mysql.erl to
erlydb_dispatcher.erl or something and then creating a
postgres_conn.erl file similar to mysql_conn.erl, but containing the
Postgres protocol logic. Anyway, these are just some ideas that might
help.

Regards,
Yariv

Roberto Saccon

unread,
Jan 16, 2007, 2:37:45 PM1/16/07
to erlyweb
I am also interested in Postgres. Brian, are you still working on your
adapter ? Can I join ?

Roberto

Brian Olsen

unread,
Jan 16, 2007, 3:59:14 PM1/16/07
to erlyweb
Here is the source code so far that I have wrote:

http://www.pushon.org/erlydb_psql.erl

It is not complete as of yet. I am planning on hacking on it later
tonight.

Brian

Roberto Saccon

unread,
Jan 17, 2007, 12:23:08 AM1/17/07
to erlyweb
ok, I just started to look at your code, Brian. And I downloaded the
driver from erlang consulting. Yariv, that is just a BSD-like-licensed
tar package, how do you bring that into the erlyweb repository ?

Roberto

Yariv Sadan

unread,
Jan 17, 2007, 12:39:47 AM1/17/07
to erl...@googlegroups.com
You can do it by setting up the svn:external property. It doesn't
import the code but it sets a pointer to the external repository,
which is then downloaded when you do 'svn update'.

Roberto Saccon

unread,
Jan 17, 2007, 1:19:08 AM1/17/07
to erlyweb
And that works for an unversioned tarfile ? I thought svn:external
works only between SVN repositories.
I guess you think setting up another google code project and
maintaining the psql driver there as you did for mysql ?

Roberto

On Jan 17, 2:39 am, "Yariv Sadan" <yari...@gmail.com> wrote:
> You can do it by setting up the svn:external property. It doesn't
> import the code but it sets a pointer to the external repository,
> which is then downloaded when you do 'svn update'.
>

Yariv Sadan

unread,
Jan 19, 2007, 5:29:47 PM1/19/07
to erl...@googlegroups.com
Yes, I thought of using svn:external to link to an external repository
in which the postgres driver would be maintained (at least initially,
until we can come up with a single-repository solution).

Yariv

On 1/17/07, Roberto Saccon <rsa...@gmail.com> wrote:
>

Roberto Saccon

unread,
Feb 5, 2007, 10:17:09 PM2/5/07
to erlyweb
Anybody did some more work here ? After just "looking" at the Erlang
consulting driver and Brian's code, I started today to play with it,
but could't get very far yet.

When starting psql I get this:


2> application:start(psql).
ok
3> Event: {psql,parameter_status,

<<99,108,105,101,110,116,95,101,110,99,111,100,105,110,103,0,85,84,70,56,0>>}
Event: {psql,parameter_status,

<<68,97,116,101,83,116,121,108,101,0,73,83,79,44,32,77,68,89,0>>}
Event: {psql,parameter_status,

<<105,110,116,101,103,101,114,95,100,97,116,101,116,105,109,101,115,0,111,110,0>>}
Event: {psql,parameter_status,

<<105,115,95,115,117,112,101,114,117,115,101,114,0,111,102,102,0>>}
Event: {psql,parameter_status,

<<115,101,114,118,101,114,95,101,110,99,111,100,105,110,103,0,85,84,70,56,0>>}
Event: {psql,parameter_status,

<<115,101,114,118,101,114,95,118,101,114,115,105,111,110,0,56,46,49,46,52,0>>}
Event: {psql,parameter_status,

<<115,101,115,115,105,111,110,95,97,117,116,104,111,114,105,122,97,116,105,111,110,0,114,115,97,99,99,111,110,0>>}
Event: {psql,parameter_status,

<<115,116,97,110,100,97,114,100,95,99,111,110,102,111,114,109,105,110,103,95,115,116,114,105,110,103,115,0,111,102,102,0>>}
Event: {psql,parameter_status,

<<84,105,109,101,90,111,110,101,0,65,109,101,114,105,99,97,47,70,111,114,116,97,108,101,122,97,0>>}
Event: {psql,backend_key_data,<<0,0,49,155,116,176,249,226>>}


Any further attempts for actual queries with psql or Brian's
erlydb_psql hang forever or fail with weired error messages, so I
guess it is some initial authorization problem. Anybody an idea how to
get a human readable error report from this psql driver ?

Roberto

Roberto Saccon

unread,
Feb 23, 2007, 3:16:50 PM2/23/07
to erlyweb
I just started a new attempt to get this postgres stuff working, this
time things went smooth (don't know why the mess at last attempt ...),
and I hope to have a working adapter soon ...

Brian Olsen

unread,
Feb 23, 2007, 7:59:17 PM2/23/07
to erlyweb

Thanks. I hope the code that I wrote will help. I just haven't had the
time to sit and concentrate on it.

Brian

Roberto Saccon

unread,
Feb 23, 2007, 8:56:19 PM2/23/07
to erlyweb
Brian, your code is helping a lot.

Yariv (and who else is familiar with this kind of stuff), the erlang-
consulting driver is a full fledged OTP app and db name / db
authentication credentials are stored in in the *.app file. The mysql
driver is just server which gets started with start_link and db name /
db authentication credentials are passed in as options.

What is the way to go ? Leave it as is ? De-OTP-ify the postgres
driver, or is it planned to OTP-ify the mysql driver ?

Roberto

Brian Olsen

unread,
Feb 24, 2007, 10:17:25 AM2/24/07
to erlyweb

One value in OTP is its configuration file support. The reason I
mention this is that I think it makes sense to utilize it more in
ErlyWeb in general. Bringing ErlyWeb closer to OTP will make it easier
to configure something like the postgres driver, and potentially, any
other driver that might come up, but you also get a general
configuration file support already available to us. :)

Brian

Yariv Sadan

unread,
Feb 24, 2007, 5:37:15 PM2/24/07
to erl...@googlegroups.com
It's not planned to OTP-ify the mysql driver. I think the best short
term solution is to make erlydb:start call application:start, etc, for
starting the postgres driver, which will read the config file to get
its configuration.

I think the ultimate solution is to take only the code for
implementing the Postgres protocol and plug it in the backend of the
MySQL dispatcher. This would provide a single connection pooling and
transaction handling mechanism for both drivers (I believe it would
also be more efficient, because AFAIK the Postgres driver relies on an
extra process to manage transaction resources, which is redundant --
it's better to just send the transaction Fun to the connection process
that executes it). However, this would require more work to pull
off...

Yariv

Roberto Saccon

unread,
Feb 25, 2007, 7:52:40 PM2/25/07
to erlyweb
to implement get_last_insert_id() for postgresql it needs to know
table name (to access a named sequence), there is no global
last_insert_id() SQL statement like in mysql, therefore I would need
to change the signature of:

Driver:get_last_insert_id(Options)

to

Driver:get_last_insert_id(Table, Options)

and provide patch erlydb_base and erlydb_mysql to work with this new
signature. Is that o.k. ?? or is there better approach for this ?

Roberto

Yariv Sadan

unread,
Feb 25, 2007, 9:01:31 PM2/25/07
to erl...@googlegroups.com
Sounds good -- the mysql driver will just ignore the Table parameter.

Yariv

Bob Ippolito

unread,
Feb 25, 2007, 9:31:39 PM2/25/07
to erl...@googlegroups.com
Semantically that's a bit off though, isn't it? PostgreSQL lets you
get the last insert id for any table at any time so long as there was
an insert to that table during that transaction (by observing the
value of the sequence).

Does erlydb know which table was inserted to last? Maybe it should
keep that state around so that it could throw an error if a MySQL user
passes in a table name that wasn't the absolute last table modified...
Better to throw an error than return an invalid number from some other
table, which you might not even catch if you were using constraints
(MySQL has those right?).

One could also use that state to allow the zero argument version for
pgsql... but as a PostgreSQL user I'd still prefer the explicit
version.

-bob

Yariv Sadan

unread,
Feb 26, 2007, 11:49:18 AM2/26/07
to erl...@googlegroups.com
ErlyDB always calls last_insert_id() immediately following an INSERT
and inside a BEGIN ... COMMIT block. I believe this guarantees that
the result of last_insert_id() is always what you expect. If not, this
needs to be fixed ASAP.

Roberto Saccon

unread,
Feb 26, 2007, 3:33:38 PM2/26/07
to erlyweb
In postgres, last_insert_id() uses SELECT CURRVAL('tablename_seq_id');
which is even session specific. I currently don't see a reason one
might receive something else than expected.

(and my postgres driver is not working yet, currently erlydb_base
crashes on do_save and lots of other problems ...)

On Feb 26, 1:49 pm, "Yariv Sadan" <yari...@gmail.com> wrote:
> ErlyDB always calls last_insert_id() immediately following an INSERT
> and inside a BEGIN ... COMMIT block. I believe this guarantees that
> the result of last_insert_id() is always what you expect. If not, this
> needs to be fixed ASAP.
>
> On 2/25/07, Bob Ippolito <b...@redivi.com> wrote:
>
>
>
> > Semantically that's a bit off though, isn't it? PostgreSQL lets you
> > get the last insert id for any table at any time so long as there was
> > an insert to that table during that transaction (by observing the
> > value of the sequence).
>
> > Does erlydb know which table was inserted to last? Maybe it should
> > keep that state around so that it could throw an error if a MySQL user
> > passes in a table name that wasn't the absolute last table modified...
> > Better to throw an error than return an invalid number from some other
> > table, which you might not even catch if you were using constraints
> > (MySQL has those right?).
>
> > One could also use that state to allow the zero argument version for
> > pgsql... but as a PostgreSQL user I'd still prefer the explicit
> > version.
>
> > -bob
>

> > On 2/25/07, Yariv Sadan <yari...@gmail.com> wrote:
>
> > > Sounds good -- the mysql driver will just ignore the Table parameter.
>
> > > Yariv
>

Yariv Sadan

unread,
Feb 27, 2007, 12:50:40 PM2/27/07
to erl...@googlegroups.com
I was responding to Bob's comment about MySQL -- I don't know how
Postgres handles this.

Roberto Saccon

unread,
Feb 27, 2007, 2:19:10 PM2/27/07
to erlyweb
Yariv, with the models created by my postgres driver in development I
currently have the following issue:

when trying to access certain fields with

myModel:myField(myModule)

it issues an erlydb_base:get/2 command with an index out of range

but if I just list the fields (e.g.: myModel:fields()) everthing looks
fine.

In case you encountered that kind of problem, while developing erlydb,
and have some hints ..

regards
Roberto

Yariv Sadan

unread,
Feb 27, 2007, 8:33:40 PM2/27/07
to erl...@googlegroups.com
ErlyDB automatically adds 2 fields to the beginning of each tuple: the
model name and whether the record has been saved in the database. So,
the actual offsets of the field is Idx + 2.

Roberto Saccon

unread,
Mar 4, 2007, 2:47:21 AM3/4/07
to erlyweb
Below is a patch for the pre-alpha version of the erlydb psql adapter.

The BSD-licensed Erlang-consulting driver I have put at
http://code.google.com/p/erlang-psql-driver/ so it can be included at
erlydb via SVN external. (Yariv, do you want me to add you there as
project owner, project member or not at all ?)

erlydb_psql basically works, but there are some major issues (such as
TEXT / VARCHARS returned as strings and not as binaries by the
driver). Next I plan to modify the Erlang-consulting driver, following
the previously in this thread suggested steps, to sort out those
issues. But before approaching that i would like to discuss what
exactly can be consolidated / refactored out, so it can be used for
any SQL-database:

- renaming mysql.erl to erlydb_dispatcher.erl

- renaming mysql.hrl to erlydb.hrl
(and change #mysql_result to #erlydb_result)

Anything else ? Other thoughts ?

Roberto

Patch:
------


Index: /home/rsaccon/eclipse-workspace/erlyweb/src/erlydb/erlydb.erl
===================================================================
--- /home/rsaccon/eclipse-workspace/erlyweb/src/erlydb/erlydb.erl
(revision 104)
+++ /home/rsaccon/eclipse-workspace/erlyweb/src/erlydb/erlydb.erl
(working copy)
@@ -128,6 +128,7 @@


driver_mod(mysql) -> erlydb_mysql;
+driver_mod(psql) -> erlydb_psql;
driver_mod(mnesia) -> erlydb_mnesia;
driver_mod(odbc) -> erlydb_odbc.

Index: /home/rsaccon/eclipse-workspace/erlyweb/src/erlydb/
erlydb_base.erl
===================================================================
--- /home/rsaccon/eclipse-workspace/erlyweb/src/erlydb/erlydb_base.erl
(revision 104)
+++ /home/rsaccon/eclipse-workspace/erlyweb/src/erlydb/erlydb_base.erl
(working copy)
@@ -1439,7 +1439,7 @@
HasIdentity = erlydb_field:extra(PkField)
== identity,
if HasIdentity ->
- case DriverMod:get_last_insert_id(
+ case DriverMod:get_last_insert_id(db_table(Module),
Options) of
{ok, Val} ->
FName = erlydb_field:name(
@@ -1448,7 +1448,7 @@
Err ->
Err
end;
- true ->
+ true ->
Rec1
end;
Err ->
Index: /home/rsaccon/eclipse-workspace/erlyweb/src/erlydb/
erlydb_field.erl
===================================================================
--- /home/rsaccon/eclipse-workspace/erlyweb/src/erlydb/
erlydb_field.erl (revision 104)
+++ /home/rsaccon/eclipse-workspace/erlyweb/src/erlydb/
erlydb_field.erl (working copy)
@@ -182,10 +182,11 @@
Field#erlydb_field.extra.

get_erl_type({Type, _Len}) -> get_erl_type(Type);
-get_erl_type(Type) ->
+get_erl_type(Type) ->
case Type of
varchar -> binary;
char -> binary;
+ 'character varying' -> binary;
binary -> binary;
varbinary -> binary;
blob -> binary;
@@ -204,6 +205,7 @@
datetime -> datetime;
date -> date;
timestamp -> datetime;
+ 'timestamp without time zone' -> datetime;
time -> time;
year -> integer;
Other -> Other
@@ -227,6 +229,7 @@
get_html_binary_input_type(Type) ->
case Type of
varchar -> text_field;
+ 'character varying' -> text_field;
char -> text_field;
binary -> text_field;
varbinary -> text_field;
Index: /home/rsaccon/eclipse-workspace/erlyweb/src/erlydb/
erlydb_mysql.erl
===================================================================
--- /home/rsaccon/eclipse-workspace/erlyweb/src/erlydb/
erlydb_mysql.erl (revision 104)
+++ /home/rsaccon/eclipse-workspace/erlyweb/src/erlydb/
erlydb_mysql.erl (working copy)
@@ -28,7 +28,7 @@
select/2,
select_as/3,
update/2,
- get_last_insert_id/1,
+ get_last_insert_id/2,
prepare/2,
execute/2,
execute/3,
@@ -301,7 +301,7 @@
%% @doc Get the id of the last inserted record.
%%
%% @spec get_last_insert_id(PoolId::atom()) -> term()
-get_last_insert_id(Options) ->
+get_last_insert_id(_Table, Options) ->
case q2(<<"SELECT last_insert_id()">>, Options) of
{data, Result} ->
[[Val]] = mysql:get_result_rows(Result),
Index: /home/rsaccon/eclipse-workspace/erlyweb/src/erlydb/
erlydb_psql.erl
===================================================================
--- /home/rsaccon/eclipse-workspace/erlyweb/src/erlydb/erlydb_psql.erl
(revision 0)
+++ /home/rsaccon/eclipse-workspace/erlyweb/src/erlydb/erlydb_psql.erl
(revision 0)
@@ -0,0 +1,287 @@
+%% @author Roberto Saccon (rsa...@gmail.com)
+%% @copyright Roberto Saccon 2007
+%%
+%% @doc This module implements the Postgresql driver for ErlyDB.
+%%
+%% Based on code initially developed by Brian Olson, see
+%% (http://groups.google.com/group/erlyweb/browse_frm/thread/
e1585240f790c87c)
+%%
+%% This is an internal ErlyDB module that you normally shouldn't have
to
+%% use directly. Configuration options are currently set via OTP
+%% Environment variables in psql.app
+%%
+
+%% For license information see LICENSE.txt
+
+-module(erlydb_psql).
+
+-author("Roberto Saccon (rsa...@gmail.com)").
+
+-export([start/0,
+ stop/0,
+ get_metadata/1,
+ get_metadata/2,
+ q/1,
+ q/2,
+ transaction/2,
+ select/2,
+ select_as/3,
+ update/2,
+ get_last_insert_id/2]).
+
+%% Useful for debugging
+
+-define(L(Msg), io:format("~p:~b ~p ~n", [?MODULE, ?LINE, Msg])).
+-define(S(Obj), io:format("LOG ~w ~s\n", [?LINE, Obj])).
+
+
+%% @doc Starts the psql and sql applications up if they are not
+%% already started. Any errors that are returned are ignored.
+
+%% @todo catch when a connection is not possible:
+%% for example, it returns {connection_failed, econnrefused}
+
+start() ->
+ application:load(sql),
+ application:load(psql),
+ application:start(sql),
+ application:start(psql).
+
+
+%% @doc Stops the psql and sql applications.
+
+stop() ->
+ application:stop(sql),
+ application:stop(psql).
+
+
+table_names_sql(SchemaName) ->
+ "select tablename from pg_tables where schemaname = '" ++ SchemaName
++ "'".
+
+column_attributes_sql(TableName) ->
+ "SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc,
a.attnotnull" ++
+ " FROM pg_attribute a LEFT JOIN pg_attrdef d" ++
+ " ON a.attrelid = d.adrelid AND a.attnum = d.adnum" ++
+ " WHERE a.attrelid = '" ++ TableName ++ "'::regclass" ++
+ " AND a.attnum > 0 AND NOT a.attisdropped" ++
+ " ORDER BY a.attnum".
+
+constraints_sql(TableName, SchemaName) ->
+ "SELECT column_name, constraint_name FROM " ++
+ "information_schema.constraint_column_usage where " ++
+ "table_name = '" ++ TableName ++ "' AND table_schema = '" ++
SchemaName ++ "'".
+
+
+%% @doc Get the table names and fields for the database.
+%%
+%% @spec get_metadata(StartOptions::proplist()) -> gb_trees()
+
+get_metadata(Options) ->
+ get_metadata(get_pool_id(Options), "public").
+
+get_metadata(PoolName, SchemaName) ->
+ TableNames = sql:q(table_names_sql(SchemaName), PoolName),
+ ConstraintInfo = lists:flatten(
+ [sql:q(constraints_sql(element(1, Name), SchemaName), PoolName) ||
+ Name <- TableNames]),
+ case catch lists:foldl(
+ fun(Table, TablesTree) ->
+ get_metadata(Table, ConstraintInfo, TablesTree, PoolName)
+ end, gb_trees:empty(), TableNames) of
+ {error, _} = Err -> Err;
+ Tree -> {ok, Tree}
+ end.
+
+get_metadata(Table, ConstraintInfo, TablesTree, PoolName) ->
+ Columns = sql:q(column_attributes_sql(element(1, Table)), PoolName),
+ Fields = [new_field(Column, element(1, Table), ConstraintInfo) ||
Column <- Columns],
+ TableName = list_to_atom(element(1, Table)),
+ gb_trees:enter(TableName, lists:reverse(Fields), TablesTree).
+
+new_field(FieldInfo, TableName, ConstraintInfo) ->
+ Name = element(1, FieldInfo),
+ Type = parse_type(element(2, FieldInfo)),
+ {Default, Extra} = parse_default(element(3, FieldInfo)),
+ NotNull = case element(4, FieldInfo) of
+ true -> false;
+ false -> true
+ end,
+ Keys = lists:map(
+ fun(Elem) ->
+ CName = TableName ++ "_pkey",
+ case element(2, Elem) of
+ CName -> element(1, Elem);
+ _ -> none
+ end
+ end,
+ ConstraintInfo),
+ Key = case lists:member(Name, Keys) of
+ true ->
+ primary;
+ _ ->
+ undefined
+ end,
+ erlydb_field:new(list_to_atom(Name), Type, NotNull, Key, Default,
Extra).
+
+
+parse_type(TypeStr) ->
+ case string:chr(TypeStr, 40) of %% 40 == '('
+ 0 ->
+ {list_to_atom(TypeStr), undefined};
+ Idx ->
+ {TypeStr1, [_| Vals]} = lists:split(Idx - 1, TypeStr),
+ {ok, [Len], _} = io_lib:fread("~d", Vals),
+ {list_to_atom(TypeStr1), Len}
+ end.
+
+
+parse_default([]) ->
+ {undefined, undefined};
+
+parse_default(DefaultStr) ->
+ case string:str(DefaultStr, "nextval") of
+ 0 ->
+ Default = hd(string:tokens(DefaultStr, "::")),
+ {Default, undefined};
+ _ ->
+ {undefined, identity}
+ end.
+
+%% @doc Execute a statement directly against the PostgreSQL driver.
If
+%% Options contains the value {allow_unsafe_sql, true}, binary and
string
+%% queries as well as ErlSQL queries with binary and/or string
expressions are
+%% accepted. Otherwise the function crashes.
+
+%% The q() functions are a direct copy from the mysql driver.
+
+q(Statement) ->
+ q(Statement, undefined).
+
+q({esql, Statement}, Options) ->
+ case allow_unsafe_statements(Options) of
+ true ->
+ {ok, q2(erlsql:unsafe_sql(Statement), Options)};
+ _ ->
+ case catch erlsql:sql(Statement) of
+ {error, _} = Err ->
+ exit(Err);
+ Sql ->
+ ?L(["Sql: ", Sql]),
+ {ok, q2(Sql, Options)}
+ end
+ end.
+
+q2(Statement, Options) ->
+ sql:q(Statement, get_pool_id(Options)).
+
+
+allow_unsafe_statements(undefined) ->
+ false;
+allow_unsafe_statements(Options) ->
+ proplists:get_value(allow_unsafe_statements, Options).
+
+get_pool_id(undefined) ->
+ erlydb_psql;
+get_pool_id(Options) ->
+ case proplists:get_value(pool_name, Options) of
+ undefined ->
+ erlydb_psql;
+ Other ->
+ Other
+ end.
+
+
+%% @doc Models a transaction. If an error occurs in the function
provided, then
+%% the transaction will rollback. Otherwise it will commit.
+
+transaction(Fun, Options) ->
+ case sql:transaction(get_pool_id(Options)) of
+ ok ->
+ Result = (catch Fun()),
+ case Result of
+ {'EXIT', Reason} ->
+ sql:rollback(get_pool_id(Options)),
+ {aborted, Reason};
+ Val ->
+ case sql:commit(get_pool_id(Options)) of
+ ok ->
+ {atomic, Val};
+ {error, Reason} ->
+ sql:rollback(get_pool_id(Options)),
+ {aborted, Reason}
+ end
+ end;
+ {error, Reason} ->
+ {aborted, Reason}
+ end.
+
+
+%% @doc Execute a raw SELECT statement.
+%%
+%% @spec select(PoolId::atom(), Statement::statement()) ->
+%% {ok, Rows::list()} | {error, Error}
+select(Statement, Options) ->
+ select2(Statement, Options, []).
+
+
+%% @doc Execute a SELECT statements for records belonging to the
given module,
+%% returning all rows with additional data to support
+%% higher-level ErlyDB features.
+%%
+%% @spec select_as(Module::atom(), Statement::statement(),
+%% FixedCols::tuple()) -> {ok, Rows} | {error, Error}
+select_as(Module, Statement, Options) ->
+ ?L(["Statement: ", Statement]),
+ select2(Statement, Options, [Module, false]).
+
+select2(Statement, Options, FixedVals) ->
+ get_select_result(q(Statement, Options), FixedVals).
+
+get_select_result({ok, _Rows}=Result, undefined) ->
+ Result;
+get_select_result({ok, Rows}, FixedVals)->
+ %% ?L(["Rows: ", Rows]),
+ Result = lists:foldl(
+ fun(Fields, Acc) ->
+ Row = FixedVals ++ tuple_to_list(Fields),
+ [list_to_tuple(Row) | Acc]
+ end, [], Rows),
+ {ok, lists:reverse(Result)};
+
+get_select_result(Other, _) ->
+ Other.
+
+
+%% @doc Execute a DELETE or UPDATE statement.
+%%
+%% @spec update(Statement::statement(), Options::options()) ->
+%% {ok, NumAffected} | {error, Err}
+%%
+%% @todo capture the number of records that were affected,
+%% instead of faking it. Requires probably modification
+%% of modify psql/sql driver to receive the result
+%% as a record as with the mysql driver.
+%%
+update(Statement, Options) ->
+ case q(Statement, Options) of
+ {ok, []} ->
+ {ok, 1};
+ {ok, {sql_error, _}=Err} ->
+ exit(Err);
+ Err ->
+ exit(Err)
+ end.
+
+
+%% @doc Get the id of the last inserted record.
+%%
+%% @spec get_last_insert_id(TableName::atom(), Options::proplist()) -
> term()
+get_last_insert_id(Table, Options) ->
+ TableName = atom_to_list(Table),
+ Sql = "SELECT currval('" ++ TableName ++ "_id_seq');",
+ case q2(Sql, Options) of
+ [{N}] ->
+ {ok, N};
+ Err ->
+ exit(Err)
+ end.
\ No newline at end of file


Yariv Sadan

unread,
Mar 4, 2007, 9:52:28 AM3/4/07
to erl...@googlegroups.com
Thank you, Roberto, for sharing this patch with us. I will look at it
closely in the next couple of days as soon as I have more time.

For now, I think we should avoid creating a fork of the Erlang
Consulting driver. The Erlang Consulting people may be more than happy
to incorporate any of our patches and even to create an svn
repository, which in the long run would be the best thing for the
community. (I have communicated about the same matter with the YXA
developers, and if/when YXA will incorporate the changes I made to the
MySQL driver, I will undo the fork). Let's ask them and then only
create a fork as a last resort.

Thanks again for sharing your work!

Cheers,
Yariv

Roberto Saccon

unread,
Mar 10, 2007, 9:33:16 PM3/10/07
to erlyweb

On Mar 4, 11:52 am, "Yariv Sadan" <yari...@gmail.com> wrote:
> Thank you, Roberto, for sharing this patch with us. I will look at it
> closely in the next couple of days as soon as I have more time.
>
> For now, I think we should avoid creating a fork of the Erlang
> Consulting driver. The Erlang Consulting people may be more than happy
> to incorporate any of our patches and even to create an svn
> repository, which in the long run would be the best thing for the
> community. (I have communicated about the same matter with the YXA
> developers, and if/when YXA will incorporate the changes I made to the
> MySQL driver, I will undo the fork). Let's ask them and then only
> create a fork as a last resort.

Huh, thats the opposite of your previous thoughts (well, that's how
things evolve)

I see two problems by not forking the Erlang consulting driver:

1) that driver seems not to be in active development, I got no answers
when trying to contact the authors of the driver, and when posting
about it on erlang mailing list I also got no replies.

2) that driver gives back a result which is differently structured
than the mysql driver, for example VARCHARS are returned as strings
(in mysql driver as binaries) and status or error messages are comming
as unfiltered binaries (and not directly human readable). I think it
would be better to fix that at the driver itself.

But I might be wrong ...

regards
Roberto

Yariv Sadan

unread,
Mar 13, 2007, 2:08:41 AM3/13/07
to erl...@googlegroups.com
> Huh, thats the opposite of your previous thoughts (well, that's how
> things evolve)

I didn't even remember I had a different position previously :)

>
> I see two problems by not forking the Erlang consulting driver:
>
> 1) that driver seems not to be in active development, I got no answers
> when trying to contact the authors of the driver, and when posting
> about it on erlang mailing list I also got no replies.
>
> 2) that driver gives back a result which is differently structured
> than the mysql driver, for example VARCHARS are returned as strings
> (in mysql driver as binaries) and status or error messages are comming
> as unfiltered binaries (and not directly human readable). I think it
> would be better to fix that at the driver itself.
>
> But I might be wrong ...
>

If you got no replies from the authors after trying to contact them,
and the existing driver is no longer developer and it isn't compatible
with ErlyDB, then I agree it's best to do the fork, at least for the
development phase. Once the fork is in good shape, and if the original
developers want to incorporate our code, then we can work with them to
merge the chages.

Thanks,
Yariv

Can Barışcan

unread,
Mar 22, 2007, 2:27:02 PM3/22/07
to erl...@googlegroups.com
Hi everyone,
I am not proficient with database drivers but I'd like to ask if somebody is working on a postgres driver?  Postgres is a must in many cases , mysql is in the treat of oracle innodb licences.  This is the buzz I heard researching on the web.  Besides postgres does better with multiple cpus and concurrency ... Don't you also think this driver is crucial?  I am working on a project and I'm waiting for this actually... Should I start with mysql and migrate later when the driver comes around? Sorry for being directive.
Can Barixcan

Roberto Saccon

unread,
Mar 22, 2007, 3:47:33 PM3/22/07
to erlyweb
I am working on it, it is nearly complete, I am using it in my app in
development instead of mysql, just a few issues are left and some of
those issues are at the base driver form Erlang Consulting. Today I
received an email from them that the have a new version in testing
which sorts out some of those remainig issues.
Well, as soon as this issues are sorted out, it will get into trunk

Roberto

On Mar 22, 3:27 pm, "Can Barışcan" <canbar...@gmail.com> wrote:
> Hi everyone,
> I am not proficient with database drivers but I'd like to ask if somebody is
> working on a postgres driver? Postgres is a must in many cases , mysql is
> in the treat of oracle innodb licences. This is the buzz I heard
> researching on the web. Besides postgres does better with multiple cpus and
> concurrency ... Don't you also think this driver is crucial? I am working
> on a project and I'm waiting for this actually... Should I start with mysql
> and migrate later when the driver comes around? Sorry for being directive.
> Can Barixcan
>

Reply all
Reply to author
Forward
0 new messages