lots of compatibility

This commit is contained in:
Adam D. Ruppe 2019-07-08 11:03:26 -04:00
parent 03315adfa6
commit acb833d724
4 changed files with 194 additions and 113 deletions

65
cgi.d
View File

@ -6076,21 +6076,24 @@ void runAddonServer(EIS)(string localListenerName, EIS eis) if(is(EIS : EventIoS
if(listen(sock, 128) == -1)
throw new Exception("listen " ~ to!string(errno));
version(linux) {
makeNonBlocking(sock);
version(linux) {
import core.sys.linux.epoll;
auto epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if(epoll_fd == -1)
throw new Exception("epoll_create1 " ~ to!string(errno));
scope(failure)
close(epoll_fd);
} else {
import core.sys.posix.poll;
}
auto acceptOp = allocateIoOp(sock, IoOp.Read, 0, null);
scope(exit)
freeIoOp(acceptOp);
version(linux) {
epoll_event ev;
ev.events = EPOLLIN | EPOLLET;
ev.data.ptr = acceptOp;
@ -6098,6 +6101,11 @@ void runAddonServer(EIS)(string localListenerName, EIS eis) if(is(EIS : EventIoS
throw new Exception("epoll_ctl " ~ to!string(errno));
epoll_event[64] events;
} else {
pollfd[] pollfds;
pollfds ~= pollfd(sock, POLLIN);
IoOp*[int] ioops;
}
while(true) {
@ -6105,24 +6113,33 @@ void runAddonServer(EIS)(string localListenerName, EIS eis) if(is(EIS : EventIoS
int timeout_milliseconds = 15000; // -1; // infinite
//writeln("waiting for ", name);
version(linux) {
auto nfds = epoll_wait(epoll_fd, events.ptr, events.length, timeout_milliseconds);
if(nfds == -1) {
if(errno == EINTR)
continue;
throw new Exception("epoll_wait " ~ to!string(errno));
}
} else {
int nfds = poll(pollfds.ptr, pollfds.length, timeout_milliseconds);
}
if(nfds == 0) {
eis.wait_timeout();
}
foreach(idx; 0 .. nfds) {
version(linux) {
auto flags = events[idx].events;
auto ioop = cast(IoOp*) events[idx].data.ptr;
} else {
auto ioop = ioops[pollfds[idx].fd];
}
//writeln(flags, " ", ioop.fd);
if(ioop.fd == sock && (flags & EPOLLIN)) {
void newConnection() {
// on edge triggering, it is important that we get it all
while(true) {
auto size = cast(uint) addr.sizeof;
@ -6136,16 +6153,40 @@ void runAddonServer(EIS)(string localListenerName, EIS eis) if(is(EIS : EventIoS
}
makeNonBlocking(ns);
epoll_event nev;
nev.events = EPOLLIN | EPOLLET;
auto niop = allocateIoOp(ns, IoOp.ReadSocketHandle, 4096, &eis.handleLocalConnectionData);
niop.closeHandler = &eis.handleLocalConnectionClose;
niop.completeHandler = &eis.handleLocalConnectionComplete;
scope(failure) freeIoOp(niop);
version(linux) {
epoll_event nev;
nev.events = EPOLLIN | EPOLLET;
nev.data.ptr = niop;
if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, ns, &nev) == -1)
throw new Exception("epoll_ctl " ~ to!string(errno));
} else {
bool found = false;
foreach(ref pfd; pollfds) {
if(pfd.fd < 0) {
pfd.fd = ns;
found = true;
}
}
if(!found)
pollfds ~= pollfd(ns, POLLIN);
}
}
}
bool newConnectionCondition() {
version(linux)
return ioop.fd == sock && (flags & EPOLLIN);
else
return pollfds[idx].fd == sock && (pollfds[idx].revents & POLLIN);
}
if(newConnectionCondition()) {
newConnection();
} else if(ioop.operation == IoOp.ReadSocketHandle) {
while(true) {
int in_fd;
@ -6161,8 +6202,16 @@ void runAddonServer(EIS)(string localListenerName, EIS eis) if(is(EIS : EventIoS
}
if(got == 0) {
if(ioop.closeHandler)
if(ioop.closeHandler) {
ioop.closeHandler(ioop);
version(linux) {} // nothing needed
else {
foreach(ref pfd; pollfds) {
if(pfd.fd == ioop.fd)
pfd.fd = -1;
}
}
}
close(ioop.fd);
freeIoOp(ioop);
break;
@ -6200,10 +6249,6 @@ void runAddonServer(EIS)(string localListenerName, EIS eis) if(is(EIS : EventIoS
// EPOLLHUP?
}
}
} else {
// this isn't seriously implemented.
static assert(0);
}
} else version(Windows) {
// set up a named pipe

View File

@ -376,8 +376,8 @@ string toSql(Database db, Variant a) {
// just for convenience; "str".toSql(db);
string toSql(string s, Database db) {
if(s is null)
return "NULL";
//if(s is null)
//return "NULL";
return '\'' ~ db.escape(s) ~ '\'';
}

View File

@ -112,6 +112,7 @@ string generateCreateTableFor(alias O)() {
static foreach(memberName; __traits(allMembers, O)) {{
alias member = __traits(getMember, O, memberName);
static if(is(typeof(member) == Constraint!constraintSql, string constraintSql)) {
version(dbgenerate_sqlite) {} else { // FIXME: make it work here too, it is the specifics of the constraint strings
if(outputted) {
sql ~= ",";
}
@ -120,6 +121,7 @@ string generateCreateTableFor(alias O)() {
sql ~= " ";
sql ~= constraintSql;
outputted = true;
}
} else static if(is(typeof(member) == Index!Fields, Fields...)) {
string fields = "";
static foreach(field; Fields) {
@ -155,26 +157,41 @@ string generateCreateTableFor(alias O)() {
else static assert(0, P.stringof);
} else static if(is(T == int))
sql ~= " INTEGER NOT NULL";
else static if(is(T == Serial))
else static if(is(T == Serial)) {
version(dbgenerate_sqlite)
sql ~= " INTEGER PRIMARY KEY AUTOINCREMENT";
else
sql ~= " SERIAL"; // FIXME postgresism
else static if(is(T == string))
} else static if(is(T == string))
sql ~= " TEXT NOT NULL";
else static if(is(T == double))
sql ~= " FLOAT NOT NULL";
else static if(is(T == bool))
sql ~= " BOOLEAN NOT NULL";
else static if(is(T == Timestamp))
else static if(is(T == Timestamp)) {
version(dbgenerate_sqlite)
sql ~= " TEXT NOT NULL";
else
sql ~= " TIMESTAMPTZ NOT NULL"; // FIXME: postgresism
else static if(is(T == enum))
} else static if(is(T == enum))
sql ~= " INTEGER NOT NULL"; // potentially crap but meh
static foreach(attr; __traits(getAttributes, member)) {
static if(is(typeof(attr) == Default)) {
// FIXME: postgresism there, try current_timestamp in sqlite
version(dbgenerate_sqlite) {
import std.string;
sql ~= " DEFAULT " ~ std.string.replace(attr.sql, "now()", "current_timestamp");
} else
sql ~= " DEFAULT " ~ attr.sql;
} else static if(is(attr == Unique)) {
sql ~= " UNIQUE";
} else static if(is(attr == PrimaryKey)) {
version(dbgenerate_sqlite) {
static if(is(T == Serial)) {} // skip, it is done above
else
addPostSql("PRIMARY KEY(" ~ memberName ~ ")");
} else
addPostSql("PRIMARY KEY(" ~ memberName ~ ")");
} else static if(is(attr == ForeignKey!(to, sqlPolicy), alias to, string sqlPolicy)) {
string refTable = toTableName(__traits(parent, to).stringof);
@ -299,9 +316,9 @@ void insert(O)(ref O t, Database db) {
} else {
// skip and let it auto-fill
}
} else static if(is(T == string))
} else static if(is(T == string)) {
builder.addVariable(memberName, __traits(getMember, t, memberName));
else static if(is(T == double))
} else static if(is(T == double))
builder.addVariable(memberName, __traits(getMember, t, memberName));
else static if(is(T == bool))
builder.addVariable(memberName, __traits(getMember, t, memberName));
@ -315,9 +332,15 @@ void insert(O)(ref O t, Database db) {
}}
import std.conv;
version(dbgenerate_sqlite) {
builder.execute(db);
foreach(row; db.query("SELECT max(id) FROM " ~ toTableName(O.stringof)))
t.id.value = to!int(row[0]);
} else {
foreach(row; builder.execute(db, "RETURNING id")) // FIXME: postgres-ism
t.id.value = to!int(row[0]);
}
}
///
class RecordNotFoundException : Exception {
@ -370,7 +393,7 @@ private void populateFromDbVal(V)(ref V val, string value) {
} else static if(is(V == Nullable!P, P)) {
// FIXME
if(value.length) {
if(value.length && value != "null") {
val.isNull = false;
val.value = to!P(value);
}

View File

@ -121,7 +121,6 @@ class Sqlite : Database {
foreach(i, arg; args) {
s.bind(cast(int) i + 1, arg);
}
return s.execute();
}
@ -263,6 +262,12 @@ struct Statement {
Sqlite db;
this(Sqlite db, string sql) {
// the arsd convention is zero based ?, but sqlite insists on one based. so this is stupid but still
if(sql.indexOf("?0") != -1) {
foreach_reverse(i; 0 .. 10)
sql = sql.replace("?" ~ to!string(i), "?" ~ to!string(i + 1));
}
this.db = db;
if(sqlite3_prepare_v2(db.db, toStringz(sql), cast(int) sql.length, &s, null) != SQLITE_OK)
throw new DatabaseException(db.error());
@ -487,14 +492,13 @@ template extract(A, T, R...){
void bind (const char[] name, float value){ bind(bindNameLookUp(name), value); }
void bind (const char[] name, const byte[] value){ bind(bindNameLookUp(name), value); }
void bind(int col, const char[] value){
if(value is null) {
void bind(int col, typeof(null) value){
if(sqlite3_bind_null(s, col) != SQLITE_OK)
throw new DatabaseException("bind " ~ db.error());
} else {
if(sqlite3_bind_text(s, col, value.ptr, cast(int) value.length, cast(void*)-1) != SQLITE_OK)
throw new DatabaseException("bind " ~ db.error());
}
void bind(int col, const char[] value){
if(sqlite3_bind_text(s, col, value.ptr is null ? "" : value.ptr, cast(int) value.length, cast(void*)-1) != SQLITE_OK)
throw new DatabaseException("bind " ~ db.error());
}
void bind(int col, float value){
@ -525,18 +529,27 @@ template extract(A, T, R...){
void bind(int col, Variant v) {
if(v.peek!long)
bind(col, v.get!long);
if(v.peek!ulong)
else if(v.peek!ulong)
bind(col, v.get!ulong);
if(v.peek!int)
else if(v.peek!int)
bind(col, v.get!int);
if(v.peek!string)
else if(v.peek!(const(int)))
bind(col, v.get!(const(int)));
else if(v.peek!bool)
bind(col, v.get!bool ? 1 : 0);
else if(v.peek!DateTime)
bind(col, v.get!DateTime.toISOExtString());
else if(v.peek!string)
bind(col, v.get!string);
if(v.peek!float)
else if(v.peek!float)
bind(col, v.get!float);
if(v.peek!(byte[]))
else if(v.peek!(byte[]))
bind(col, v.get!(byte[]));
if(v.peek!(void*) && v.get!(void*) is null)
bind(col, cast(string) null);
else if(v.peek!(void*) && v.get!(void*) is null)
bind(col, null);
else
bind(col, v.coerce!string);
//assert(0, v.type.toString ~ " " ~ v.coerce!string);
}
~this(){