1 #include "Sql.h"
2 
3 namespace Upp {
4 
5 #define LLOG(x) // DLOG(x)
6 
SqlToBool(const String & s)7 bool SqlToBool(const String& s) {
8 	return !(IsNull(s) || *s == '0' && s[1] == '\0');
9 }
10 
SqlToBool(const Value & v)11 bool SqlToBool(const Value& v) {
12 	if(IsNull(v)) return false;
13 	if(IsString(v)) return SqlToBool(String(v));
14 	if(IsNumber(v)) return (int) v;
15 	return true;
16 }
17 
BoolToSql(bool b)18 const String& BoolToSql(bool b) {
19 	static String T("1"), F("0");
20 	return b ? T : F;
21 }
22 
Field(Ref f)23 void FieldOperator::Field(Ref f) {}
24 
Field(const char * name,Ref f)25 void FieldOperator::Field(const char *name, Ref f) { Field(f); }
26 
Field(const char * name,Ref f,bool * b)27 void FieldOperator::Field(const char *name, Ref f, bool *b) { Field(name, f); }
28 
Width(int width)29 void FieldOperator::Width(int width) {}
30 
31 
operator ()(const char * name,bool & b)32 FieldOperator& FieldOperator::operator()(const char *name, bool& b) {
33 	String x = BoolToSql(b);
34 	Field(name, x, &b);
35 	b = SqlToBool(x);
36 	return *this;
37 }
38 
39 static char sql_error[] = "Database error";
40 
41 #ifndef NOAPPSQL
SqlExc()42 SqlExc::SqlExc() : Exc(sql_error) {
43 	SetSessionError(SQL.GetSession());
44 }
45 #endif
46 
SqlExc(const SqlSession & session)47 SqlExc::SqlExc(const SqlSession& session) : Exc(sql_error) {
48 	SetSessionError(session);
49 }
50 
SqlExc(const Sql & sql)51 SqlExc::SqlExc(const Sql& sql) : Exc(sql_error) {
52 	SetSessionError(sql.GetSession());
53 }
54 
SetSessionError(const SqlSession & session)55 void SqlExc::SetSessionError(const SqlSession& session) {
56 	if(session.WasError())
57 		*this = session.GetLastError();
58 	else
59 		*this = String(sql_error);
60 	*this << "\nSQL error: " << session.GetErrorStatement();
61 }
62 
SqlConnection()63 SqlConnection::SqlConnection()  { parse = true; fetchrows = 32; longsize = 16384; }
~SqlConnection()64 SqlConnection::~SqlConnection() {}
65 
Cancel()66 void SqlConnection::Cancel() {}
67 
GetRowsProcessed() const68 int  SqlConnection::GetRowsProcessed() const {
69 	NEVER();
70 	return 0;
71 }
72 
GetUser() const73 String SqlConnection::GetUser() const {
74 	NEVER();
75 	return Null;
76 }
77 
GetInsertedId() const78 Value SqlConnection::GetInsertedId() const
79 {
80 	NEVER();
81 	return Null;
82 }
83 
Compile(const SqlStatement & s)84 String Sql::Compile(const SqlStatement& s)
85 {
86 	byte dialect = GetDialect();
87 	ASSERT(dialect);
88 	return s.Get(dialect);
89 }
90 
Clear()91 void Sql::Clear() {
92 	if(cn) {
93 		cn->Cancel();
94 		cn->parse = true;
95 	}
96 }
97 
SetParam(int i,const Value & val)98 void Sql::SetParam(int i, const Value& val) {
99 	cn->SetParam(i, val);
100 	if(GetSession().GetTrace())
101 		param.Set(i, val);
102 }
103 
SetStatement(const String & s)104 void Sql::SetStatement(const String& s) {
105 	cn->statement = s;
106 	cn->parse = true;
107 }
108 
Execute()109 bool Sql::Execute() {
110 	SqlSession &session = GetSession();
111 
112 	session.SetStatement(cn->statement);
113 	session.SetStatus(SqlSession::BEFORE_EXECUTING);
114 	cn->starttime = msecs();
115 	Stream *s = session.GetTrace();
116 	if(s) {
117 #ifndef NOAPPSQL
118 		if(this == &AppCursor())
119 			*s << "SQL* ";
120 		else
121 		if(this == &AppCursorR())
122 			*s << "SQLR* ";
123 #endif
124 		String st = cn->statement;
125 		if(session.IsTraceCompression())
126 			st = CompressLog(st);
127 		int i = 0;
128 		for(const char *q = st; *q; q++)
129 			if(*q == '?' && i < param.GetCount()) {
130 				Value v = param[i++];
131 				if(IsString(v))
132 					*s << '\'' << v << '\'';
133 				else
134 					*s << v;
135 			}
136 			else
137 				s->Put(*q);
138 		*s << '\n';
139 	}
140 	if(!session.IsOpen())
141 	{
142 		session.SetStatus(SqlSession::CONNECTION_ERROR);
143 		return false;
144 	}
145 	session.SetStatus(SqlSession::START_EXECUTING);
146 	bool b = cn->Execute();
147 	session.SetTime(msecs() - cn->starttime);
148 	session.SetStatus(SqlSession::END_EXECUTING);
149 	if(!b)
150 		session.SetStatus(SqlSession::EXECUTING_ERROR);
151 	for(int i = 0; i < cn->info.GetCount(); i++)
152 		cn->info[i].name = ToUpper(cn->info[i].name);
153 
154 	session.SetStatus(SqlSession::AFTER_EXECUTING);
155 	if(!b && session.throwonerror)
156 		throw SqlExc(GetSession());
157 	return b;
158 }
159 
ExecuteX()160 void Sql::ExecuteX() {
161 	if(!Execute())
162 		throw SqlExc(GetSession());
163 }
164 
Execute(const String & s)165 bool Sql::Execute(const String& s) {
166 	SetStatement(s);
167 	return Execute();
168 }
169 
ExecuteX(const String & s)170 void Sql::ExecuteX(const String& s) {
171 	SetStatement(s);
172 	ExecuteX();
173 }
174 
175 //$-
176 
177 #define E__SetParam(I)    SetParam(I - 1, p##I)
178 
179 #define E__RunF(I) \
180 bool Sql::Run(__List##I(E__Value)) { \
181 	__List##I(E__SetParam); \
182 	return Run(); \
183 }
184 __Expand(E__RunF)
185 
186 #define E__RunFX(I) \
187 void Sql::RunX(__List##I(E__Value)) { \
188 	__List##I(E__SetParam); \
189 	RunX(); \
190 }
__Expand(E__RunFX)191 __Expand(E__RunFX)
192 
193 #define E__ExecuteF(I) \
194 bool Sql::Execute(const String& s, __List##I(E__Value)) { \
195 	SetStatement(s); \
196 	__List##I(E__SetParam); \
197 	return Execute(); \
198 }
199 __Expand(E__ExecuteF)
200 
201 #define E__ExecuteFX(I) \
202 void Sql::ExecuteX(const String& s, __List##I(E__Value)) { \
203 	SetStatement(s); \
204 	__List##I(E__SetParam); \
205 	ExecuteX(); \
206 }
207 __Expand(E__ExecuteFX)
208 
209 //$+
210 
211 bool Sql::Fetch() {
212 	SqlSession& session = GetSession();
213 	session.SetStatus(SqlSession::START_FETCHING);
214 
215 	dword t0 = msecs();
216 	bool b = cn->Fetch();
217 	dword t = msecs();
218 
219 	dword total = cn->starttime == INT_MAX ? 0 : t - cn->starttime;
220 	dword fetch = t - t0;
221 
222 	session.SetStatus(SqlSession::END_FETCHING);
223 	if(!b) {
224 		session.SetTime(total);
225 		session.SetStatus(SqlSession::END_FETCHING_MANY);
226 	}
227 	Stream *s = session.GetTrace();
228 	if(s) {
229 		if((int)total > session.traceslow)
230 			*s << "SLOW SQL: " << total << " ms: " << cn->statement << UPP::EOL;
231 		else
232 		if((int)fetch > session.traceslow)
233 			*s << "SLOW SQL: " << fetch << " ms further fetch: " << cn->statement << UPP::EOL;
234 	}
235 	cn->starttime = INT_MAX;
236 	return b;
237 }
238 
239 //$-
240 #define E__GetColumn(I) cn->GetColumn(I - 1, p##I)
241 
242 #define E__FetchF(I) \
243 bool Sql::Fetch(__List##I(E__Ref)) { \
244 	if(!Fetch()) return false; \
245 	__List##I(E__GetColumn); \
246 	return true; \
247 }
__Expand(E__FetchF)248 __Expand(E__FetchF)
249 //$+
250 
251 Vector<Value> Sql::GetRow() const {
252 	Vector<Value> row;
253 	int n = GetColumns();
254 	row.SetCount(n);
255 	for(int i = 0; i < n; i++)
256 		row[i] = (*this)[i];
257 	return row;
258 }
259 
Fetch(Vector<Value> & row)260 bool Sql::Fetch(Vector<Value>& row) {
261 	if(!Fetch()) return false;
262 	row = GetRow();
263 	return true;
264 }
265 
GetRowMap() const266 ValueMap Sql::GetRowMap() const
267 {
268 	ValueMap m;
269 	int n = GetColumns();
270 	for(int i = 0; i < n; i++)
271 		m.Add(GetColumnInfo(i).name, (*this)[i]);
272 	return m;
273 }
274 
operator %(const SqlStatement & q)275 Value Sql::operator%(const SqlStatement& q)
276 {
277 	return Select0(Compile(q));
278 }
279 
operator ^(const SqlStatement & q)280 ValueMap Sql::operator^(const SqlStatement& q)
281 {
282 	Execute(q);
283 	ValueMap m;
284 	Fetch(m);
285 	return m;
286 }
287 
operator /(const SqlStatement & q)288 ValueArray Sql::operator/(const SqlStatement& q)
289 {
290 	ValueArray va;
291 	Execute(q);
292 	ValueMap m;
293 	while(Fetch(m))
294 		va.Add(m);
295 	return va;
296 }
297 
Fetch(ValueMap & row)298 bool Sql::Fetch(ValueMap& row) {
299 	if(!Fetch()) return false;
300 	row = GetRowMap();
301 	return true;
302 }
303 
304 struct sReadFields : public FieldOperator {
305 	Sql *sql;
306 
FieldUpp::sReadFields307 	void Field(const char *name, Ref f) {
308 		sql->GetColumn(SqlId(name), f);
309 	}
310 };
311 
Get(Fields fo)312 void Sql::Get(Fields fo)
313 {
314 	sReadFields ff;
315 	ff.sql = this;
316 	fo(ff);
317 }
318 
Fetch(Fields fo)319 bool Sql::Fetch(Fields fo) {
320 	if(!Fetch()) return false;
321 	Get(fo);
322 	return true;
323 }
324 
GetColumnCount() const325 int Sql::GetColumnCount() const
326 {
327 	return cn->info.GetCount();
328 }
329 
GetColumns() const330 int  Sql::GetColumns() const {
331 	return GetColumnCount();
332 }
333 
GetColumn(int i,Ref r) const334 void Sql::GetColumn(int i, Ref r) const {
335 	cn->GetColumn(i, r);
336 }
337 
GetColumn(SqlId colid,Ref r) const338 void Sql::GetColumn(SqlId colid, Ref r) const
339 {
340 	String s = ~colid;
341 	for(int j = 0; j < 2; j++) {
342 		for(int i = 0; i < cn->info.GetCount(); i++)
343 			if(cn->info[i].name == s) {
344 				GetColumn(i, r);
345 				return;
346 			}
347 		s = ToUpper(s);
348 	}
349 	r.SetNull();
350 }
351 
operator [](int i) const352 Value Sql::operator[](int i) const {
353 	Value v;
354 	cn->GetColumn(i, v);
355 	return v;
356 }
357 
operator [](SqlId id) const358 Value Sql::operator[](SqlId id) const {
359 	String s = ~id;
360 	for(int j = 0; j < 2; j++) {
361 		for(int i = 0; i < cn->info.GetCount(); i++)
362 			if(cn->info[i].name == s)
363 				return operator[](i);
364 		s = ToUpper(s);
365 	}
366 	NEVER_(String().Cat() << "SQL [" << ~id << "] not found");
367 	return Value();
368 }
369 
Select0(const String & s)370 Value Sql::Select0(const String& s) {
371 	SetStatement(s);
372 	if(!Run())
373 		return ErrorValue(GetLastError());
374 	if(!Fetch())
375 		return Null;
376 	Value v;
377 	cn->GetColumn(0, v);
378 	return v;
379 }
380 
Select(const String & s)381 Value Sql::Select(const String& s) {
382 	return Select0("select " + s);
383 }
384 
385 //$-
386 #define E__SelectF(I) \
387 Value Sql::Select(const String& s, __List##I(E__Value)) { \
388 	__List##I(E__SetParam); \
389 	return Select(s); \
390 }
391 __Expand(E__SelectF)
392 
393 #define E__Inserter(I)  clist += ", ", clist += c##I, qlist += ", ?", SetParam(I, v##I)
394 
395 #define E__InsertF(I) \
396 bool Sql::Insert(const char *table, const char *c0, const Value& v0, __List##I(E__ColVal)) { \
397 	String  clist = c0; \
398 	String  qlist = "?"; \
399 	SetParam(0, v0); \
400 	__List##I(E__Inserter); \
401 	return Execute(String("insert into ") + table + '(' + clist + ") values(" + qlist + ')'); \
402 }
__Expand(E__InsertF)403 __Expand(E__InsertF)
404 
405 #define E__InserterId(I)  clist += ", ", clist += c##I.ToString(), qlist += ", ?", SetParam(I, v##I)
406 
407 #define E__InsertIdF(I) \
408 bool Sql::Insert(SqlId table, SqlId c0, const Value& v0, __List##I(E__IdVal)) { \
409 	String  clist = c0.ToString(); \
410 	String  qlist = "?"; \
411 	SetParam(0, v0); \
412 	__List##I(E__InserterId); \
413 	return Execute( \
414 			String("insert into ") + table.ToString() + '(' + clist + ") values(" + qlist + ')'); \
415 }
416 __Expand(E__InsertIdF)
417 
418 static inline void sComma(int I, String& s) {
419 	if(I > 1) s.Cat(", ");
420 }
421 
422 #define E__Updater(I)  sComma(I, list), list.Cat(c##I), list.Cat(" = ?"), SetParam(I - 1, v##I)
423 
424 #define  E__UpdateF(I) \
425 bool Sql::Update(const char *table, const char *key, const Value& keyval, __List##I(E__ColVal)) { \
426 	String list; \
427 	__List##I(E__Updater); \
428 	SetParam(I, keyval); \
429 	return Execute(String ("update ") + table + " set " + list + " where " + key + " = ?"); \
430 }
431 __Expand(E__UpdateF)
432 
433 #define E__UpdaterId(I)  sComma(I, list), list.Cat(c##I.ToString()), list.Cat(" = ?"), SetParam(I - 1, v##I)
434 
435 #define  E__UpdateIdF(I) \
436 bool Sql::Update(SqlId table, SqlId key, const Value& keyval, __List##I(E__IdVal)) { \
437 	String list; \
438 	__List##I(E__UpdaterId); \
439 	SetParam(I, keyval); \
440 	return Execute(String ("update ") + table.ToString() + \
441 	               " set " + list + " where " + key.ToString() + " = ?"); \
442 }
__Expand(E__UpdateIdF)443 __Expand(E__UpdateIdF)
444 //$+
445 
446 bool Sql::Delete(const char *table, const char *key, const Value& keyval) {
447 	return Execute("delete from " + String(table) + " where " + key + " = ?", keyval);
448 }
449 
Delete(SqlId table,SqlId key,const Value & keyval)450 bool Sql::Delete(SqlId table, SqlId key, const Value& keyval) {
451 	return Delete(~table.ToString(), ~key.ToString(), keyval);
452 }
453 
GetDialect() const454 int Sql::GetDialect() const {
455 	return GetSession().GetDialect();
456 }
457 
458 struct NfInsert : public FieldOperator {
459 	int    i;
460 	Sql   *sql;
461 	String clist;
462 	String qlist;
463 
FieldUpp::NfInsert464 	virtual void Field(const char *name, Ref f) {
465 		if(i) {
466 			clist += ", ";
467 			qlist += ", ";
468 		}
469 		clist += name;
470 		qlist += "? ";
471 		sql->SetParam(i++, f);
472 	}
473 };
474 
Insert(Fields nf,const char * table)475 bool Sql::Insert(Fields nf, const char *table) {
476 	NfInsert w;
477 	w.i = 0;
478 	w.sql = this;
479 	nf(w);
480 	return Execute(String("insert into ") + (table ? String(table) : w.table) +
481 	               '(' + w.clist + ") values(" + w.qlist + ')');
482 }
483 
Insert(Fields nf)484 bool Sql::Insert(Fields nf) {
485 	return Insert(nf, NULL);
486 }
487 
Insert(Fields nf,SqlId table)488 bool Sql::Insert(Fields nf, SqlId table) {
489 	return Insert(nf, (const char *)~table);
490 }
491 
492 struct NfInsertNoKey : public FieldOperator {
493 	int    i;
494 	Sql   *sql;
495 	String clist;
496 	String qlist;
497 
FieldUpp::NfInsertNoKey498 	virtual void Field(const char *name, Ref f) {
499 		if(clist.GetCount()) {
500 			clist += ", ";
501 			qlist += ", ";
502 		}
503 		if(i) {
504 			clist += name;
505 			qlist += "? ";
506 			sql->SetParam(i - 1, f);
507 		}
508 		i++;
509 	}
510 };
511 
InsertNoKey(Fields nf,const char * table)512 bool Sql::InsertNoKey(Fields nf, const char *table) {
513 	NfInsertNoKey w;
514 	w.i = 0;
515 	w.sql = this;
516 	nf(w);
517 	return Execute(String("insert into ") + (table ? String(table) : w.table) +
518 	               '(' + w.clist + ") values(" + w.qlist + ')');
519 }
520 
InsertNoKey(Fields nf)521 bool Sql::InsertNoKey(Fields nf) {
522 	return InsertNoKey(nf, NULL);
523 }
524 
InsertNoKey(Fields nf,SqlId table)525 bool Sql::InsertNoKey(Fields nf, SqlId table) {
526 	return InsertNoKey(nf, (const char *)~table);
527 }
528 
529 struct NfInsertNoNulls : public FieldOperator {
530 	int    i;
531 	Sql   *sql;
532 	String clist;
533 	String qlist;
534 
FieldUpp::NfInsertNoNulls535 	virtual void Field(const char *name, Ref f) {
536 		if(!f.IsNull()) {
537 			if(clist.GetCount()) {
538 				clist += ", ";
539 				qlist += ", ";
540 			}
541 			clist << name;
542 			qlist << "? ";
543 			sql->SetParam(i++, f);
544 		}
545 	}
546 };
547 
InsertNoNulls(Fields nf,const char * table)548 bool Sql::InsertNoNulls(Fields nf, const char *table)
549 {
550 	NfInsertNoNulls w;
551 	w.i = 0;
552 	w.sql = this;
553 	nf(w);
554 	return Execute(String("insert into ") + (table ? String(table) : w.table) +
555 	               '(' + w.clist + ") values(" + w.qlist + ')');
556 }
557 
InsertNoNulls(Fields nf)558 bool Sql::InsertNoNulls(Fields nf)
559 {
560 	return InsertNoNulls(nf, NULL);
561 }
562 
InsertNoNulls(Fields nf,SqlId table)563 bool Sql::InsertNoNulls(Fields nf, SqlId table)
564 {
565 	return InsertNoNulls(nf, (const char *)~table);
566 }
567 
568 #define E__Updater(I)  sComma(I, list), list.Cat(c##I), list.Cat(" = ?"), SetParam(I - 1, v##I)
569 
570 struct NfUpdate : public FieldOperator {
571 	int    i;
572 	Sql   *sql;
573 	String list;
574 	String key;
575 	Value  keyval;
576 
FieldUpp::NfUpdate577 	virtual void Field(const char *name, Ref f) {
578 		if(i == 0) {
579 			key = name;
580 			keyval = f;
581 		}
582 		else {
583 			if(i > 1)
584 				list += ", ";
585 			list << name << " = ?";
586 			sql->SetParam(i - 1, f);
587 		}
588 		i++;
589 	}
590 };
591 
Update(Fields nf,const char * table)592 bool Sql::Update(Fields nf, const char *table) {
593 	NfUpdate w;
594 	w.i = 0;
595 	w.sql = this;
596 	nf(w);
597 	SetParam(w.i - 1, w.keyval);
598 	return Execute(String ("update ") + (table ? String(table) : w.table) +
599 	               " set " + w.list + " where " + w.key + " = ?");
600 }
601 
Update(Fields nf)602 bool Sql::Update(Fields nf) {
603 	return Update(nf, NULL);
604 }
605 
Update(Fields nf,SqlId table)606 bool Sql::Update(Fields nf, SqlId table) {
607 	return Update(nf, (const char *)~table);
608 }
609 
SetSession(SqlSource & s)610 void Sql::SetSession(SqlSource& s) {
611 	Detach();
612 	cn = s.CreateConnection();
613 }
614 
SetError(String err,String stmt,int code,const char * scode,ERRORCLASS clss)615 void Sql::SetError(String err, String stmt, int code, const char *scode, ERRORCLASS clss)
616 {
617 	GetSession().SetError(err, stmt, code, scode, clss);
618 }
619 
ClearError()620 void   Sql::ClearError()                          { GetSession().ClearError(); }
621 
GetLastError() const622 String Sql::GetLastError() const                  { return GetSession().GetLastError(); }
GetErrorStatement() const623 String Sql::GetErrorStatement() const             { return GetSession().GetErrorStatement(); }
GetErrorCode() const624 int    Sql::GetErrorCode() const                  { return GetSession().GetErrorCode(); }
GetErrorCodeString() const625 String Sql::GetErrorCodeString() const            { return GetSession().GetErrorCodeString(); }
GetErrorClass() const626 Sql::ERRORCLASS Sql::GetErrorClass() const        { return GetSession().GetErrorClass(); }
WasError() const627 bool   Sql::WasError() const                      { return GetSession().WasError(); }
628 
Begin()629 void   Sql::Begin()                               { ClearError(); GetSession().Begin(); }
Commit()630 void   Sql::Commit()                              { GetSession().Commit(); }
Rollback()631 void   Sql::Rollback()                            { GetSession().Rollback(); }
GetTransactionLevel()632 int    Sql::GetTransactionLevel()                 { return GetSession().GetTransactionLevel(); }
633 
Savepoint()634 String Sql::Savepoint()                           { return GetSession().Savepoint(); }
RollbackTo(const String & savepoint)635 void   Sql::RollbackTo(const String& savepoint)   { GetSession().RollbackTo(savepoint); }
636 
IsOpen()637 bool   Sql::IsOpen()                              { return cn && GetSession().IsOpen(); }
638 
Attach(Sql & sql,SqlConnection * con)639 void SqlConnection::Attach(Sql& sql, SqlConnection *con)
640 {
641 	sql.Attach(con); // Duck tape to fix Oci8
642 }
643 
644 #ifndef NOAPPSQL
Sql()645 Sql::Sql() {
646 	cn = NULL;
647 	if(SQL.cn)
648 		cn = SQL.GetSession().CreateConnection();
649 }
650 #endif
651 
Sql(SqlSource & s)652 Sql::Sql(SqlSource& s) {
653 	cn = s.CreateConnection();
654 }
655 
656 #ifndef NOAPPSQL
Sql(const char * stmt)657 Sql::Sql(const char *stmt) {
658 	cn = SQL.GetSession().CreateConnection();
659 	SetStatement(stmt);
660 }
661 #endif
662 
Sql(const char * stmt,SqlSource & s)663 Sql::Sql(const char *stmt, SqlSource& s) {
664 	cn = s.CreateConnection();
665 	SetStatement(stmt);
666 }
667 
668 #ifndef NOAPPSQL
Sql(const SqlStatement & stmt)669 Sql::Sql(const SqlStatement& stmt) {
670 	cn = SQL.GetSession().CreateConnection();
671 	SetStatement(stmt);
672 }
673 #endif
674 
Sql(const SqlStatement & stmt,SqlSource & s)675 Sql::Sql(const SqlStatement& stmt, SqlSource& s) {
676 	cn = s.CreateConnection();
677 	SetStatement(stmt);
678 }
679 
Sql(SqlConnection * connection)680 Sql::Sql(SqlConnection *connection)
681 : cn(connection)
682 {}
683 
Detach()684 void Sql::Detach()
685 {
686 	if(cn) delete cn;
687 	cn = NULL;
688 	param.Clear();
689 }
690 
Attach(SqlConnection * connection)691 void Sql::Attach(SqlConnection *connection)
692 {
693 	Detach();
694 	cn = connection;
695 }
696 
~Sql()697 Sql::~Sql() {
698 	Detach();
699 }
700 
701 #ifndef NOAPPSQL
702 
SqlR()703 SqlR::SqlR()
704 :	Sql(SQLR.GetSession()) {}
705 
SqlR(const char * stmt)706 SqlR::SqlR(const char *stmt)
707 :	Sql(stmt, SQLR.GetSession()) {}
708 
SqlR(const SqlStatement & s)709 SqlR::SqlR(const SqlStatement& s)
710 :	Sql(s, SQLR.GetSession()) {}
711 
712 #endif
713 
714 #ifndef NOAPPSQL
operator *=(ValueMap & map,SqlSelect select)715 void operator*=(ValueMap& map, SqlSelect select)
716 {
717 	map.Clear();
718 	Sql sql;
719 	sql * select;
720 	while(sql.Fetch())
721 		map.Add(sql[0], sql[1]);
722 }
723 #endif
724 
725 }
726