Sql: SqlMassInsert (using 'union all' trick)

git-svn-id: svn://ultimatepp.org/upp/trunk@2597 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2010-08-07 14:52:40 +00:00
parent 9216fdd6b3
commit a50feb3f05
4 changed files with 119 additions and 0 deletions

87
uppsrc/Sql/MassInsert.cpp Normal file
View file

@ -0,0 +1,87 @@
#include "Sql.h"
namespace Upp {
SqlMassInsert::~SqlMassInsert()
{
Flush();
}
SqlMassInsert& SqlMassInsert::operator()(SqlId col, const Value& val)
{
if(pos == 0) {
cache.Add().nulls = 0;
cache.Top();
}
if(cache.GetCount() == 1)
column.Add(~col);
else
ASSERT(column[pos] == ~col);
Row& r = cache.Top();
r.value.Add(val);
if(IsNull(val))
r.nulls |= (1 << pos);
pos++;
ASSERT(pos < 30);
return *this;
}
SqlMassInsert& SqlMassInsert::EndRow()
{
if(cache.GetCount() && cache[0].value.GetCount() * cache.GetCount() > 5000)
Flush();
ASSERT(column.GetCount() == pos);
pos = 0;
return *this;
}
void SqlMassInsert::Flush()
{
const dword DONE = 0xffffffff;
if(cache.GetCount() == 0)
return;
for(int ii = 0; ii < cache.GetCount(); ii++) {
dword nulls = cache[ii].nulls;
if(nulls != DONE) {
String insert;
insert << "insert into " + table + '(';
bool nextcol = false;
for(int i = 0; i < column.GetCount(); i++) {
if(!(nulls & (1 << i))) {
if(nextcol)
insert << ", ";
nextcol = true;
insert << column[i];
}
}
insert << ')';
bool nextsel = false;
for(int i = ii; i < cache.GetCount(); i++) {
Row& r = cache[i];
if(r.nulls == nulls) {
r.nulls = DONE;
if(nextsel)
insert << " union all";
nextsel = true;
insert << " select ";
bool nextval = false;
for(int i = 0; i < r.value.GetCount(); i++)
if(!(nulls & (1 << i))) {
if(nextval)
insert << ", ";
nextval = true;
insert << SqlCompile(sql.GetDialect(), SqlFormat(r.value[i]));
}
if(sql.GetDialect() == ORACLE)
insert << " from dual";
}
}
sql.Execute(insert);
}
}
cache.Clear();
column.Clear();
pos = 0;
}
};

View file

@ -18,6 +18,7 @@ file
SqlStatement.cpp,
Sqls.h,
Sql.cpp,
MassInsert.cpp,
Schema readonly separator,
SqlSchema.h,
SqlSchema.cpp,

View file

@ -94,6 +94,8 @@ void SqlCompile(const char *&s, StringBuffer *r, byte dialect)
case ORACLE:
*r << Format("to_date('%d/%d/%d', 'SYYYY/MM/DD')", x.year, x.month, x.day);
break;
case PGSQL:
*r << "date ";
default:
*r << Format("\'%04d-%02d-%02d\'", x.year, x.month, x.day);
}
@ -119,6 +121,8 @@ void SqlCompile(const char *&s, StringBuffer *r, byte dialect)
*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;
case PGSQL:
*r << "timestamp ";
default:
*r << Format("\'%04d-%02d-%02d %02d:%02d:%02d\'",
x.year, x.month, x.day, x.hour, x.minute, x.second);

View file

@ -389,3 +389,30 @@ StatementExecutor& SQLStatementExecutor();
typedef Sql QSql;
typedef SqlSession QSession;
#endif
class SqlMassInsert {
struct Row : Moveable<Row> {
dword nulls;
Vector <Value> value;
};
Sql& sql;
String table;
Vector<String> column;
Vector<Row> cache;
int pos;
void NewRow();
public:
SqlMassInsert& operator()(SqlId col, const Value& val);
SqlMassInsert& EndRow();
void Flush();
SqlMassInsert(Sql& sql, SqlId table) : sql(sql), table(~table) { pos = 0; }
#ifndef NOAPPSQL
SqlMassInsert(SqlId table) : sql(SQL), table(~table) { pos = 0; }
#endif
~SqlMassInsert();
};