#include "Sql.h" NAMESPACE_UPP enum { SQLC_IF = 1, SQLC_ELSEIF, SQLC_ELSE, SQLC_ENDIF, SQLC_DATE, SQLC_TIME, SQLC_STRING, }; template String MakeSqlValue(int code, T& value) { StringBuffer b(sizeof(T) + 1); b[0] = code; memcpy(~b + 1, &value, sizeof(T)); return b; } template T ReadSqlValue(T& x, const char *&s) { memcpy(&x, s, sizeof(T)); s += sizeof(T); return x; } static String SqlFormat__(const char *s, int res, bool mysql) { if(!s || !*s) return "NULL"; String result; result.Reserve(res); result.Cat("\'"); for(; *s; s++) { if(*s == '\'') result.Cat(mysql ? "\\\'" : "\'\'"); else { if((*s == '\"' || *s == '\\') && mysql) result.Cat('\\'); result.Cat(*s); } } result.Cat('\''); return result; } void SqlCompile(const char *&s, StringBuffer *r, byte dialect) { for(;;) { int c = *s++; switch(c) { case SQLC_IF: { StringBuffer *er = r; for(;;) { c = *s++; if(c & dialect) { SqlCompile(s, er, dialect); er = NULL; } else SqlCompile(s, NULL, dialect); if(*s == '\0') return; c = *s++; if(c == SQLC_ELSE) { SqlCompile(s, er, dialect); ASSERT(*s == SQLC_ENDIF); s++; break; } if(c == SQLC_ENDIF) break; ASSERT(c == SQLC_ELSEIF); } } break; case SQLC_DATE: { Date x; ReadSqlValue(x, s); if(!r) break; if(IsNull(x)) { *r << "NULL"; break; } switch(dialect) { case MSSQL: if(x.year < 1753) x.year = 1753; // Date::Low() *r << Format("convert(datetime, '%d/%d/%d', 120)", x.year, x.month, x.day); break; case ORACLE: *r << Format("to_date('%d/%d/%d', 'SYYYY/MM/DD')", x.year, x.month, x.day); break; default: *r << Format("\'%04d-%02d-%02d\'", x.year, x.month, x.day); } break; } case SQLC_TIME: { Time x; ReadSqlValue(x, s); if(!r) break; if(IsNull(x)) { *r << "NULL"; break; } switch(dialect) { case MSSQL: if(x.year < 1753) x.year = 1753; // Date::Low() *r << Format(x.hour || x.minute || x.second ? "convert(datetime, '%d/%d/%d %d:%d:%d', 120)" : "convert(datetime, '%d/%d/%d', 120)", x.year, x.month, x.day, x.hour, x.minute, x.second); break; case ORACLE: *r << Format("to_date('%d/%d/%d/%d', 'SYYYY/MM/DD/SSSSS')", x.year, x.month, x.day, x.second + 60 * (x.minute + 60 * x.hour)); break; default: *r << Format("\'%04d-%02d-%02d %02d:%02d:%02d\'", x.year, x.month, x.day, x.hour, x.minute, x.second); } break; } case SQLC_STRING: { int l; ReadSqlValue(l, s); String x = String(s, l); s += l; if(!r) break; if(IsNull(x)) { *r << "NULL"; break; } r->Cat('\''); for(const char *q = x; *q; q++) { if(*q == '\'') { if(dialect == MY_SQL) r->Cat("\\\'"); else if(dialect == PGSQL) r->Cat("\\'"); else r->Cat("\'\'"); } else { if((*q == '\"' || *q == '\\') && dialect == MY_SQL) r->Cat('\\'); r->Cat(*q); } } r->Cat('\''); break; } default: if(c >= 0 && c < 32) { s--; return; } else if(r) r->Cat(c); } } } String SqlCompile(byte dialect, const String& s) { StringBuffer b; b.Reserve(s.GetLength() + 100); const char *q = s; SqlCompile(q, &b, dialect); return b; } String SqlFormat(int x) { if(IsNull(x)) return "NULL"; return Format("%d", x); } String SqlFormat(double x) { if(IsNull(x)) return "NULL"; return FormatDouble(x, 20); } String SqlFormat(int64 x) { if(IsNull(x)) return "NULL"; return FormatInt64(x); } String SqlFormat(const char *s, int l) { StringBuffer b(1 + sizeof(int) + l); b[0] = SQLC_STRING; memcpy(~b + 1, &l, sizeof(int)); memcpy(~b + 1 + sizeof(int), s, l); return b; } String SqlFormat(const char *s) { return SqlFormat(s, strlen(s)); } String SqlFormat(const String& x) { return SqlFormat(x, x.GetLength()); } String SqlFormat(Date x) { return MakeSqlValue(SQLC_DATE, x); } String SqlFormat(Time x) { return MakeSqlValue(SQLC_TIME, x); } String SqlFormat(const Value& x) { if(x.IsNull()) return "NULL"; switch(x.GetType()) { case BOOL_V: case INT_V: return SqlFormat((int) x); case INT64_V: return SqlFormat((int64) x); case DOUBLE_V: return SqlFormat((double) x); case STRING_V: case WSTRING_V: return SqlFormat(String(x)); case DATE_V: return SqlFormat(Date(x)); case TIME_V: return SqlFormat(Time(x)); } NEVER(); return "NULL"; } String SqlCase::operator()(const String& text) { return s << (char)SQLC_ELSE << text << (char)SQLC_ENDIF; } String SqlCase::operator()() { return s << (char)SQLC_ENDIF; } SqlCase SqlCase::operator()(byte cond, const String& text) { s << (char)SQLC_ELSEIF << (char)cond << text; return *this; } SqlCase::SqlCase(byte cond, const String& text) { s << (char)SQLC_IF << (char)cond << text; } END_UPP_NAMESPACE