mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 22:02:49 -06:00
262 lines
4.8 KiB
C++
262 lines
4.8 KiB
C++
#include "Sql.h"
|
|
|
|
NAMESPACE_UPP
|
|
|
|
enum {
|
|
SQLC_IF = 1,
|
|
SQLC_ELSEIF,
|
|
SQLC_ELSE,
|
|
SQLC_ENDIF,
|
|
SQLC_DATE,
|
|
SQLC_TIME,
|
|
SQLC_STRING,
|
|
};
|
|
|
|
template <class T>
|
|
String MakeSqlValue(int code, T& value)
|
|
{
|
|
StringBuffer b(sizeof(T) + 1);
|
|
b[0] = code;
|
|
memcpy(~b + 1, &value, sizeof(T));
|
|
return b;
|
|
}
|
|
|
|
template <class T>
|
|
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
|