|
|
|
|
|
|
#pike 8.1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define ERROR(X ...) predef::error(X) |
|
|
object master_sql; |
|
|
|
|
|
|
|
|
|
|
int(0..1) case_convert; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function(string:string) quote = .sql_util.quote; |
|
|
|
|
|
|
|
|
|
|
|
function(int,void|int:string) encode_time; |
|
|
|
|
|
|
|
|
|
function(string,void|int:int) decode_time; |
|
|
|
|
|
|
|
function(int:string) encode_date; |
|
|
|
|
|
|
function(string:int) decode_date; |
|
|
|
|
|
|
|
function(int:string) encode_datetime; |
|
|
|
|
|
|
function(string:int) decode_datetime; |
|
protected program find_dbm(string program_name) { |
program p; |
|
p = Sql[program_name]; |
if(!p && Sql["Provider"] && Sql["Provider"][program_name]) |
p = Sql["Provider"][program_name][program_name]; |
return p; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void create(string|object host, void|string|mapping(string:int|string) db, |
void|string user, void|string _password, |
void|mapping(string:int|string) options) |
{ |
|
|
string password = _password; |
_password = "CENSORED"; |
|
if (objectp(host)) { |
master_sql = host; |
if ((user && user != "") || (password && password != "") || |
(options && sizeof(options))) { |
ERROR("Only the database argument is supported when " |
"first argument is an object.\n"); |
} |
if (db && db != "") { |
master_sql->select_db(db); |
} |
} |
else { |
if (mappingp(db)) { |
options = db; |
db = 0; |
} |
if (db == "") { |
db = 0; |
} |
if (user == "") { |
user = 0; |
} |
if (password == "") { |
password = 0; |
} |
|
string program_name; |
|
if (host && (host != replace(host, ([ ":":"", "/":"", "@":"" ]) ))) { |
|
|
|
|
|
array(string) arr = host/"://"; |
if ((sizeof(arr) > 1) && (arr[0] != "")) { |
if (sizeof(arr[0]/".pike") > 1) { |
program_name = (arr[0]/".pike")[0]; |
} else { |
program_name = arr[0]; |
} |
host = arr[1..] * "://"; |
} |
arr = host/"@"; |
if (sizeof(arr) > 1) { |
|
host = arr[-1]; |
arr = (arr[..<1]*"@")/":"; |
if (!user && sizeof(arr[0])) { |
user = arr[0]; |
} |
if (!password && (sizeof(arr) > 1)) { |
password = arr[1..]*":"; |
if (password == "") { |
password = 0; |
} |
} |
} |
arr = host/"/"; |
if (sizeof(arr) > 1) { |
host = arr[..<1]*"/"; |
if (!db) { |
db = arr[-1]; |
} |
} |
} |
|
if (host == "") { |
host = 0; |
} |
|
if (!program_name) { |
ERROR("No protocol specified.\n"); |
} |
|
if ((sizeof(program_name / "_result") != 1) || |
((< "Sql", "sql", "sql_util", "module" >)[program_name]) ) { |
ERROR("Unsupported protocol %O.\n", program_name); |
} |
|
|
program p; |
|
if (p = find_dbm(program_name)) { |
if (options) { |
master_sql = p(host||"", db||"", user||"", password||"", options); |
} else if (password) { |
master_sql = p(host||"", db||"", user||"", password); |
} else if (user) { |
master_sql = p(host||"", db||"", user); |
} else if (db) { |
master_sql = p(host||"", db); |
} else if (host) { |
master_sql = p(host); |
} else { |
master_sql = p(); |
} |
if (!master_sql->query && !master_sql->big_query) { |
master_sql = UNDEFINED; |
ERROR("Failed to index module Sql.%s or Sql.Provider.%s.\n", |
program_name, program_name); |
} |
} else { |
ERROR("Failed to index module Sql.%s or Sql.Provider.%s.\n", |
program_name, program_name); |
} |
} |
|
if (master_sql->quote) quote = master_sql->quote; |
encode_time = master_sql->encode_time || .sql_util.fallback; |
decode_time = master_sql->decode_time || .sql_util.fallback; |
encode_date = master_sql->encode_date || .sql_util.fallback; |
decode_date = master_sql->decode_date || .sql_util.fallback; |
encode_datetime = master_sql->encode_datetime || .sql_util.fallback; |
decode_datetime = master_sql->decode_datetime || .sql_util.fallback; |
} |
|
protected void _destruct() { |
if (master_sql) |
destruct(master_sql); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
int is_open() |
{ |
if (!master_sql) return 0; |
if (master_sql->is_open) return master_sql->is_open(); |
return 1; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int ping() |
{ |
if (!master_sql) return -1; |
if (master_sql->ping) return master_sql->ping(); |
catch { |
return sizeof(query("SELECT 0 AS zero") || ({})) - 1; |
}; |
master_sql = UNDEFINED; |
return -1; |
} |
|
void set_charset (string charset) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
if (!master_sql->set_charset) |
predef::error ("This database connection does not " |
"support charset switching.\n"); |
master_sql->set_charset (charset); |
} |
|
string get_charset() |
|
|
|
|
|
|
|
{ |
return master_sql->get_charset && master_sql->get_charset(); |
} |
|
protected string _sprintf(int type, mapping|void flags) |
{ |
if(type=='O' && master_sql && master_sql->_sprintf) |
return sprintf("Sql.%O", master_sql); |
} |
|
protected array(mapping(string:mixed)) res_obj_to_array(object res_obj) |
{ |
if (!res_obj) |
return 0; |
|
array(mapping(string:mixed)) res = ({}); |
while (res_obj) |
{ |
|
array(string) fieldnames; |
array(mixed) row; |
|
array(mapping) fields = res_obj->fetch_fields(); |
if(!sizeof(fields)) return ({}); |
|
int has_table = fields[0]->table && fields[0]->table!=""; |
|
if(has_table) |
fieldnames = (map(fields, |
lambda (mapping(string:mixed) m) { |
return (m->table||"") + "." + m->name; |
}) + |
fields->name); |
else |
fieldnames = fields->name; |
|
if (case_convert) |
fieldnames = map(fieldnames, lower_case); |
|
if(has_table) |
while (row = res_obj->fetch_row()) |
res += ({ mkmapping(fieldnames, row + row) }); |
else |
while (row = res_obj->fetch_row()) |
res += ({ mkmapping(fieldnames, row) }); |
|
|
res_obj = res_obj->next_result && res_obj->next_result(); |
} |
return res; |
} |
|
|
int|string error() |
{ |
if (master_sql && functionp (master_sql->error)) |
return master_sql->error(); |
return "Unknown error"; |
} |
|
|
|
|
string sqlstate() { |
if (master_sql && functionp(master_sql->sqlstate)) { |
return master_sql->sqlstate(); |
} |
return "IM001"; |
} |
|
|
void select_db(string db) |
{ |
master_sql->select_db(db); |
} |
|
|
|
|
|
|
|
|
|
|
|
string|object compile_query(string q) |
{ |
if (functionp(master_sql->compile_query)) { |
return master_sql->compile_query(q); |
} |
return q; |
} |
|
array(string|mapping(string|int:mixed)) |
handle_extraargs(string query, array(mixed) extraargs) |
|
{ |
return .sql_util.handle_extraargs (query, extraargs); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
array(mapping(string:string)) query(object|string q, |
mixed ... extraargs) |
{ |
if (sizeof(extraargs)) { |
mapping(string|int:mixed) bindings; |
|
if (mappingp(extraargs[0])) |
bindings=extraargs[0]; |
else |
[q,bindings]=.sql_util.handle_extraargs(q,extraargs); |
|
if(bindings) { |
if(master_sql->query) |
return master_sql->query(q, bindings); |
return res_obj_to_array(master_sql->big_query(q, bindings)); |
} |
} |
|
if (master_sql->query) |
return master_sql->query(q); |
return res_obj_to_array(master_sql->big_query(q)); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
array(mapping(string:mixed)) typed_query(object|string q, mixed ... extraargs) |
{ |
if (!master_sql->big_typed_query) |
ERROR ("Typed mode not supported by the backend %O.\n", master_sql); |
|
if (sizeof(extraargs)) { |
mapping(string|int:mixed) bindings; |
|
if (mappingp(extraargs[0])) |
bindings=extraargs[0]; |
else |
[q,bindings]=.sql_util.handle_extraargs(q,extraargs); |
|
if(bindings) { |
if(master_sql->typed_query) |
return master_sql->typed_query(q, bindings); |
return res_obj_to_array(master_sql->big_typed_query(q, bindings)); |
} |
} |
|
if (master_sql->typed_query) |
return master_sql->typed_query(q); |
return res_obj_to_array(master_sql->big_typed_query(q)); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int|object big_query(object|string q, mixed ... extraargs) |
{ |
mapping(string|int:mixed) bindings; |
|
if (sizeof(extraargs)) { |
if (mappingp(extraargs[0])) |
bindings = extraargs[0]; |
else |
[q, bindings] = .sql_util.handle_extraargs(q, extraargs); |
} |
|
object|array(mapping) pre_res; |
|
if(bindings) { |
if(master_sql->big_query) |
pre_res = master_sql->big_query(q, bindings); |
else |
pre_res = master_sql->query(q, bindings); |
} else { |
if (master_sql->big_query) |
pre_res = master_sql->big_query(q); |
else |
pre_res = master_sql->query(q); |
} |
|
if(pre_res) { |
if(objectp(pre_res)) |
return .sql_object_result(pre_res); |
else |
return .sql_array_result(pre_res); |
} |
return 0; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int|object big_typed_query(object|string q, mixed ... extraargs) |
{ |
if (!master_sql->big_typed_query) |
ERROR ("Typed mode not supported by the backend %O.\n", master_sql); |
|
mapping(string|int:mixed) bindings; |
|
if (sizeof(extraargs)) { |
if (mappingp(extraargs[0])) |
bindings = extraargs[0]; |
else |
[q, bindings] = .sql_util.handle_extraargs(q, extraargs); |
} |
|
object|array(mapping) pre_res; |
|
if (bindings) { |
pre_res = master_sql->big_typed_query(q, bindings); |
} else { |
pre_res = master_sql->big_typed_query(q); |
} |
|
if(pre_res) return .sql_object_result(pre_res); |
return 0; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int|object streaming_query(object|string q, mixed ... extraargs) |
{ |
if(!master_sql->streaming_query) return big_query(q, @extraargs); |
|
mapping(string|int:mixed) bindings; |
|
if (sizeof(extraargs)) { |
if(mappingp(extraargs[0])) |
bindings = extraargs[0]; |
else |
[q, bindings] = .sql_util.handle_extraargs(q, extraargs); |
} |
|
object pre_res; |
|
if(bindings) { |
pre_res = master_sql->streaming_query(q, bindings); |
} else { |
pre_res = master_sql->streaming_query(q); |
} |
|
if(pre_res) return .sql_object_result(pre_res); |
return 0; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int|object streaming_typed_query(object|string q, mixed ... extraargs) |
{ |
if(!master_sql->streaming_typed_query) return big_typed_query(q, @extraargs); |
|
mapping(string|int:mixed) bindings; |
|
if (sizeof(extraargs)) { |
if(mappingp(extraargs[0])) |
bindings = extraargs[0]; |
else |
[q, bindings] = .sql_util.handle_extraargs(q, extraargs); |
} |
|
object pre_res; |
|
if(bindings) { |
pre_res = master_sql->streaming_typed_query(q, bindings); |
} else { |
pre_res = master_sql->streaming_typed_query(q); |
} |
|
if(pre_res) return .sql_object_result(pre_res); |
return 0; |
} |
|
|
|
|
|
void create_db(string db) |
{ |
master_sql->create_db(db); |
} |
|
|
|
|
|
void drop_db(string db) |
{ |
master_sql->drop_db(db); |
} |
|
|
void shutdown() |
{ |
if (functionp(master_sql->shutdown)) { |
master_sql->shutdown(); |
} else { |
ERROR("Not supported by this database.\n"); |
} |
} |
|
|
void reload() |
{ |
if (functionp(master_sql->reload)) { |
master_sql->reload(); |
} else { |
|
} |
} |
|
|
string server_info() |
{ |
if (functionp(master_sql->server_info)) { |
return master_sql->server_info() ; |
} |
return "Unknown SQL-server"; |
} |
|
|
string host_info() |
{ |
if (functionp(master_sql->host_info)) { |
return master_sql->host_info(); |
} |
return "Unknown connection to host"; |
} |
|
|
|
|
|
array(string) list_dbs(string|void wild) |
{ |
array(string)|array(mapping(string:mixed))|object res; |
|
if (functionp(master_sql->list_dbs)) { |
if (objectp(res = master_sql->list_dbs())) { |
res = res_obj_to_array(res); |
} |
} else { |
catch { |
res = query("show databases"); |
}; |
} |
if (res && sizeof(res) && mappingp(res[0])) { |
res = map(res, lambda (mapping m) { |
return values(m)[0]; |
} ); |
} |
if (res && wild) { |
res = filter(res, |
Regexp(replace(wild, ({"%", "_"}), ({".*", "."})))->match); |
} |
return res; |
} |
|
|
|
|
|
array(string) list_tables(string|void wild) |
{ |
array(string)|array(mapping(string:mixed))|object res; |
|
if (functionp(master_sql->list_tables)) { |
if (objectp(res = master_sql->list_tables())) { |
res = res_obj_to_array(res); |
} |
} else { |
catch { |
res = query("show tables"); |
}; |
} |
if (res && sizeof(res) && mappingp(res[0])) { |
string col_name = indices(res[0])[0]; |
if (sizeof(res[0]) > 1) { |
if (!zero_type(res[0]["TABLE_NAME"])) { |
|
col_name = "TABLE_NAME"; |
} |
} |
res = map(res, lambda (mapping m, string col_name) { |
return m[col_name]; |
}, col_name); |
} |
if (res && wild) { |
res = filter(res, |
Regexp(replace(wild, ({"%", "_"}), ({".*", "."})))->match); |
} |
return res; |
} |
|
|
|
|
|
|
|
|
array(mapping(string:mixed)) list_fields(string table, string|void wild) |
{ |
array(mapping(string:mixed))|object res; |
|
if (functionp(master_sql->list_fields)) { |
if (objectp(res = master_sql->list_fields(table))) { |
res = res_obj_to_array(res); |
} |
if (wild) { |
res = filter(res, |
lambda(mapping row, function(string:int) match) { |
return match(row->name); |
}, |
Regexp(replace(wild, ({"%", "_"}), ({".*", "."})))->match); |
} |
return res; |
} |
catch { |
if (wild) { |
res = query("show fields from \'" + table + |
"\' like \'" + wild + "\'"); |
} else { |
res = query("show fields from \'" + table + "\'"); |
} |
}; |
res = res && map(res, lambda (mapping m, string table) { |
foreach(indices(m), string str) { |
|
string low_str = lower_case(str); |
if (low_str != str && !m[low_str]) |
m[low_str] = m_delete(m, str); |
} |
|
if ((!m->name) && m->field) |
m["name"] = m_delete(m, "field"); |
|
if (!m->table) |
m["table"] = table; |
|
return m; |
}, table); |
return res; |
} |
|
|