Begin support for other constraints than PRIMARY KEY
This commit is contained in:
15575
erl_crash.dump
Normal file
15575
erl_crash.dump
Normal file
File diff suppressed because one or more lines are too long
@@ -602,8 +602,20 @@ build_table_info([], Acc) ->
|
|||||||
lists:reverse(Acc);
|
lists:reverse(Acc);
|
||||||
build_table_info([[ColName, ColType] | Tl], Acc) ->
|
build_table_info([[ColName, ColType] | Tl], Acc) ->
|
||||||
build_table_info(Tl, [{list_to_atom(ColName), sqlite3_lib:col_type_to_atom(ColType)}| Acc]);
|
build_table_info(Tl, [{list_to_atom(ColName), sqlite3_lib:col_type_to_atom(ColType)}| Acc]);
|
||||||
build_table_info([[ColName, ColType, "PRIMARY", "KEY"] | Tl], Acc) ->
|
build_table_info([[ColName, ColType | Constraints] | Tl], Acc) ->
|
||||||
build_table_info(Tl, [{list_to_atom(ColName), sqlite3_lib:col_type_to_atom(ColType), primary_key} | Acc]).
|
build_table_info(Tl, [{list_to_atom(ColName), sqlite3_lib:col_type_to_atom(ColType), build_constraints(Constraints)} | Acc]).
|
||||||
|
|
||||||
|
%% TODO conflict-clause parsing
|
||||||
|
build_constraints([]) -> [];
|
||||||
|
build_constraints(["PRIMARY", "KEY", "ASC" | Tail]) -> [primary_key | build_constraints(Tail)];
|
||||||
|
build_constraints(["PRIMARY", "KEY", "DESC" | Tail]) -> [{primary_key, desc} | build_constraints(Tail)];
|
||||||
|
build_constraints(["PRIMARY", "KEY" | Tail]) -> [primary_key | build_constraints(Tail)];
|
||||||
|
build_constraints(["UNIQUE" | Tail]) -> [unique | build_constraints(Tail)];
|
||||||
|
build_constraints(["NOT", "NULL" | Tail]) -> [not_null | build_constraints(Tail)];
|
||||||
|
build_constraints(["DEFAULT", DefaultValue | Tail]) -> [{default, sqlite3_lib:sql_to_value(DefaultValue)} | build_constraints(Tail)].
|
||||||
|
% build_constraints(["CHECK", Check | Tail]) -> ...
|
||||||
|
% build_constraints(["REFERENCES", Check | Tail]) -> ...
|
||||||
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @type sql_value() = number() | 'null' | iodata().
|
%% @type sql_value() = number() | 'null' | iodata().
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
%% API
|
%% API
|
||||||
-export([col_type_to_atom/1]).
|
-export([col_type_to_atom/1]).
|
||||||
-export([value_to_sql/1, value_to_sql_unsafe/1, escape/1]).
|
-export([value_to_sql/1, value_to_sql_unsafe/1, sql_to_value/1, escape/1]).
|
||||||
-export([write_value_sql/1, write_col_sql/1]).
|
-export([write_value_sql/1, write_col_sql/1]).
|
||||||
-export([create_table_sql/2, write_sql/2, read_sql/3, delete_sql/3, drop_table/1]).
|
-export([create_table_sql/2, write_sql/2, read_sql/3, delete_sql/3, drop_table/1]).
|
||||||
-export([update_sql/4, update_set_sql/1]).
|
-export([update_sql/4, update_set_sql/1]).
|
||||||
@@ -89,6 +89,30 @@ value_to_sql(X) ->
|
|||||||
true -> [$', escape(X), $']
|
true -> [$', escape(X), $']
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% @spec sql_to_value(String :: string()) -> sql_value()
|
||||||
|
%% @doc
|
||||||
|
%% Converts an SQL value to an Erlang term.
|
||||||
|
%% @end
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
sql_to_value(String) ->
|
||||||
|
case String of
|
||||||
|
"NULL" -> null;
|
||||||
|
"CURRENT_TIME" -> current_time;
|
||||||
|
"CURRENT_DATE" -> current_date;
|
||||||
|
"CURRENT_TIMESTAMP" -> current_timestamp;
|
||||||
|
[FirstChar | Tail] ->
|
||||||
|
case FirstChar of
|
||||||
|
$' -> sql_string(Tail);
|
||||||
|
$x -> sql_blob(Tail);
|
||||||
|
$X -> sql_blob(Tail);
|
||||||
|
$+ -> sql_number(Tail);
|
||||||
|
$- -> -sql_number(Tail);
|
||||||
|
Digit when $0 =< Digit, Digit =< $9 -> sql_number(Tail)
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @spec write_value_sql(Value :: [term()]) -> iolist()
|
%% @spec write_value_sql(Value :: [term()]) -> iolist()
|
||||||
%% @doc
|
%% @doc
|
||||||
@@ -99,6 +123,7 @@ value_to_sql(X) ->
|
|||||||
write_value_sql(Values) ->
|
write_value_sql(Values) ->
|
||||||
map_intersperse(fun value_to_sql/1, Values, ",").
|
map_intersperse(fun value_to_sql/1, Values, ",").
|
||||||
|
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @spec write_col_sql([atom()]) -> iolist()
|
%% @spec write_col_sql([atom()]) -> iolist()
|
||||||
%% @doc Creates the column/data stmt for SQL.
|
%% @doc Creates the column/data stmt for SQL.
|
||||||
@@ -258,6 +283,27 @@ map_intersperse(_Fun, [], _Sep) -> [];
|
|||||||
map_intersperse(Fun, [Elem], _Sep) -> [Fun(Elem)];
|
map_intersperse(Fun, [Elem], _Sep) -> [Fun(Elem)];
|
||||||
map_intersperse(Fun, [Head | Tail], Sep) -> [Fun(Head), Sep | map_intersperse(Fun, Tail, Sep)].
|
map_intersperse(Fun, [Head | Tail], Sep) -> [Fun(Head), Sep | map_intersperse(Fun, Tail, Sep)].
|
||||||
|
|
||||||
|
-spec sql_number(string()) -> number() | {error, not_a_number}.
|
||||||
|
sql_number(NumberStr) ->
|
||||||
|
case string:to_integer(NumberStr) of
|
||||||
|
{Int, []} ->
|
||||||
|
Int;
|
||||||
|
Other ->
|
||||||
|
case string:to_float(NumberStr) of
|
||||||
|
{Float, []} ->
|
||||||
|
Float;
|
||||||
|
Other ->
|
||||||
|
{error, not_a_number}
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
-spec sql_string(string()) -> string().
|
||||||
|
sql_string(StringWithEscapedQuotes) ->
|
||||||
|
re:replace(StringWithEscapedQuotes, "'(?!')", "", [global, {return, list}]).
|
||||||
|
|
||||||
|
-spec sql_blob(string()) -> string().
|
||||||
|
sql_blob(Blob) -> Blob.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% @type sql_value() = number() | 'null' | iodata().
|
%% @type sql_value() = number() | 'null' | iodata().
|
||||||
%%
|
%%
|
||||||
|
|||||||
2
test.erl
2
test.erl
@@ -8,7 +8,7 @@ test() ->
|
|||||||
sqlite3:open(ct),
|
sqlite3:open(ct),
|
||||||
sqlite3:create_table(ct, user, [{id, integer}, {name, text}, {age, integer}, {wage, integer}]),
|
sqlite3:create_table(ct, user, [{id, integer}, {name, text}, {age, integer}, {wage, integer}]),
|
||||||
[user] = sqlite3:list_tables(ct),
|
[user] = sqlite3:list_tables(ct),
|
||||||
[{id, integer, primary_key}, {name, text}, {age, integer}, {wage, integer}] = sqlite3:table_info(ct, user),
|
[{id, integer, [primary_key]}, {name, text}, {age, integer}, {wage, integer}] = sqlite3:table_info(ct, user),
|
||||||
{id, Id1} = sqlite3:write(ct, user, [{name, "abby"}, {age, 20}, {wage, 2000}]),
|
{id, Id1} = sqlite3:write(ct, user, [{name, "abby"}, {age, 20}, {wage, 2000}]),
|
||||||
Id1 = 1,
|
Id1 = 1,
|
||||||
{id, Id2} = sqlite3:write(ct, user, [{name, "marge"}, {age, 30}, {wage, 2000}]),
|
{id, Id2} = sqlite3:write(ct, user, [{name, "marge"}, {age, 30}, {wage, 2000}]),
|
||||||
|
|||||||
Reference in New Issue
Block a user