Line data Source code
1 : /**
2 : Copyright (c) 2018-2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023-2024 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #include "SPSqlHandle.h"
25 : #include "SPSqlDriver.h"
26 : #include "SPDbScheme.h"
27 :
28 : namespace STAPPLER_VERSIONIZED stappler::db::sql {
29 :
30 : template <typename Clause>
31 : static void SqlQuery_makeCustomFrom(const Driver *driver, SqlQuery &q, Clause &tmp, const Query &query, const Scheme &scheme);
32 :
33 3650 : static bool Handle_hasPostUpdate(const SpanView<InputField> &idata, const SpanView<InputRow> &inputRows) {
34 3650 : size_t i = 0;
35 33775 : for (auto &it : idata) {
36 30425 : auto t = it.field->getType();
37 30425 : switch (t) {
38 50 : case db::Type::Array:
39 : case db::Type::Set:
40 50 : for (auto &row : inputRows) {
41 50 : if (row.values[i].hasValue()) {
42 50 : return true;
43 : }
44 : }
45 0 : return true;
46 : break;
47 250 : case db::Type::Object:
48 500 : for (auto &row : inputRows) {
49 250 : if (row.values[i].hasValue() && !row.values[i].value.isBasicType()) {
50 0 : return true;
51 : }
52 : }
53 250 : break;
54 30125 : default:
55 30125 : break;
56 : }
57 30375 : if (t == db::Type::Array || t == db::Type::Set || t == db::Type::Object) {
58 250 : return true;
59 : }
60 30125 : ++ i;
61 : }
62 3350 : return false;
63 : }
64 :
65 6175 : static Value Handle_preparePostUpdate(const Vector<InputField> &inputFields, InputRow &row) {
66 6175 : Value postUpdate(Value::Type::DICTIONARY);
67 6175 : size_t i = 0;
68 42525 : for (auto &field : inputFields) {
69 36350 : switch (field.field->getType()) {
70 75 : case db::Type::Array:
71 : case db::Type::Set:
72 75 : if (row.values[i].hasValue()) {
73 50 : postUpdate.setValue(std::move(row.values[i].value), field.field->getName());
74 : }
75 75 : break;
76 375 : case db::Type::Object:
77 375 : if (row.values[i].hasValue() && !row.values[i].value.isBasicType()) {
78 0 : postUpdate.setValue(std::move(row.values[i].value), field.field->getName());
79 : }
80 375 : break;
81 35900 : default:
82 35900 : break;
83 : }
84 36350 : ++ i;
85 : }
86 :
87 6175 : return postUpdate;
88 0 : }
89 :
90 0 : bool SqlHandle::foreach(Worker &worker, const Query &q, const Callback<bool(Value &)> &cb) {
91 0 : auto queryStorage = _driver->makeQueryStorage(worker.scheme().getName());
92 0 : bool ret = false;
93 0 : auto &scheme = worker.scheme();
94 0 : makeQuery([&, this] (SqlQuery &query) {
95 0 : auto ordField = q.getQueryField();
96 0 : if (ordField.empty()) {
97 0 : SqlQuery::Context ctx(query, scheme, worker, q);
98 0 : query.writeQuery(ctx);
99 0 : ret = selectQuery(query, [&] (Result &res) -> bool {
100 0 : auto virtuals = ctx.getVirtuals();
101 0 : for (auto it : res) {
102 0 : auto d = it.toData(scheme, Map<String, db::Field>(), virtuals);
103 0 : if (!cb(d)) {
104 0 : return false;
105 : }
106 0 : }
107 0 : return true;
108 0 : });
109 0 : } else if (auto f = scheme.getField(ordField)) {
110 0 : switch (f->getType()) {
111 0 : case Type::Set: {
112 0 : SqlQuery::Context ctx(query, *f->getForeignScheme(), worker, q);
113 0 : if (query.writeQuery(ctx, scheme, q.getQueryId(), *f)) {
114 0 : ret = selectQuery(query, [&] (Result &res) -> bool {
115 0 : auto virtuals = ctx.getVirtuals();
116 0 : for (auto it : res) {
117 0 : auto d = it.toData(*f->getForeignScheme(), Map<String, db::Field>(), virtuals);
118 0 : if (!cb(d)) {
119 0 : return false;
120 : }
121 0 : }
122 0 : return true;
123 0 : });
124 : }
125 0 : break;
126 0 : }
127 0 : default:
128 0 : break;
129 : }
130 : }
131 0 : }, &queryStorage);
132 0 : return ret;
133 0 : }
134 :
135 6249 : Value SqlHandle::select(Worker &worker, const db::Query &q) {
136 6249 : auto queryStorage = _driver->makeQueryStorage(worker.scheme().getName());
137 :
138 6250 : Value ret;
139 6250 : auto &scheme = worker.scheme();
140 6250 : makeQuery([&, this] (SqlQuery &query) {
141 6250 : auto ordField = q.getQueryField();
142 6250 : if (ordField.empty()) {
143 6200 : SqlQuery::Context ctx(query, scheme, worker, q);
144 6200 : query.writeQuery(ctx);
145 6200 : ret = selectValueQuery(scheme, query, ctx.getVirtuals());
146 6250 : } else if (auto f = scheme.getField(ordField)) {
147 50 : switch (f->getType()) {
148 0 : case Type::Set:
149 0 : ret = getSetField(worker, query, q.getQueryId(), *f, q);
150 0 : break;
151 50 : case Type::View:
152 50 : ret = getViewField(worker, query, q.getQueryId(), *f, q);
153 50 : break;
154 0 : default:
155 0 : break;
156 : }
157 : }
158 6250 : }, &queryStorage);
159 12500 : return ret;
160 6250 : }
161 :
162 3650 : Value SqlHandle::create(Worker &worker, const Vector<InputField> &inputFields, Vector<InputRow> &inputRows, bool multiCreate) {
163 3650 : if (inputRows.empty() || inputFields.empty()) {
164 0 : return Value();
165 : }
166 :
167 3650 : auto queryStorage = _driver->makeQueryStorage(worker.scheme().getName());
168 :
169 3650 : auto &scheme = worker.scheme();
170 :
171 3675 : auto bindRow = [&] (Value &ret, stappler::sql::Query<Binder,Interface>::InsertValues &val, InputRow &input) {
172 34550 : for (size_t idx = 0; idx < inputFields.size(); ++ idx) {
173 30875 : auto f = inputFields[idx].field;
174 30875 : switch (f->getType()) {
175 50 : case Type::Set:
176 : case Type::Array:
177 : case Type::Virtual:
178 50 : break;
179 30825 : default:
180 30825 : switch (input.values[idx].type) {
181 28375 : case InputValue::Type::Value: {
182 28375 : auto &v = ret.setValue(input.values[idx].value, f->getName());
183 28375 : val.value(db::Binder::DataField{f, v, f->isDataLayout(), f->hasFlag(db::Flags::Compressed)});
184 28375 : break;
185 : }
186 0 : case InputValue::Type::File:
187 : case InputValue::Type::None:
188 0 : val.def();
189 0 : break;
190 2450 : case InputValue::Type::TSV:
191 2450 : val.value(db::Binder::FullTextField{f, input.values[idx].tsv});
192 2450 : break;
193 : }
194 30825 : break;
195 : }
196 : }
197 3675 : };
198 :
199 7250 : auto perform = [&, this] (InputRow &row) {
200 3625 : int64_t id = 0;
201 3625 : Value ret;
202 3625 : Value postUpdate(Handle_preparePostUpdate(inputFields, row));
203 :
204 3625 : makeQuery([&, this] (SqlQuery &query) {
205 3625 : auto ins = query.insert(scheme.getName());
206 34350 : for (auto &it : inputFields) {
207 30725 : switch (it.field->getType()) {
208 50 : case Type::Set:
209 : case Type::Array:
210 : case Type::Virtual:
211 50 : break;
212 30675 : default:
213 30675 : ins.field(it.field->getName());
214 30675 : break;
215 : }
216 : }
217 :
218 3625 : auto val = ins.values();
219 3625 : bindRow(ret, val, row);
220 :
221 3625 : auto &conflicts = worker.getConflicts();
222 3725 : for (auto &it : conflicts) {
223 100 : if (it.second.isDoNothing()) {
224 50 : val.onConflict(it.first->getName()).doNothing();
225 : } else {
226 50 : auto c = val.onConflict(it.first->getName()).doUpdate();
227 550 : for (auto &iit : ret.asDict()) {
228 500 : auto f = scheme.getField(iit.first);
229 500 : if (f && (it.second.mask.empty() || std::find(it.second.mask.begin(), it.second.mask.end(), f) != it.second.mask.end())) {
230 500 : c.excluded(iit.first);
231 : }
232 : }
233 :
234 50 : if (it.second.hasCondition()) {
235 0 : c.where().parenthesis(db::Operator::And, [&] (SqlQuery::WhereBegin &wh) {
236 0 : SqlQuery::WhereContinue iw(wh.query, wh.state);
237 0 : query.writeWhereCond(iw, db::Operator::And, worker.scheme(), it.second.condition);
238 0 : });
239 : }
240 : }
241 : }
242 :
243 3625 : if (id == 0) {
244 3625 : val.returning().field(SqlQuery::Field("__oid").as("id")).finalize();
245 3625 : id = selectQueryId(query);
246 3625 : if (id) {
247 3625 : if (worker.shouldIncludeNone() && worker.scheme().hasForceExclude()) {
248 0 : for (auto &it : worker.scheme().getFields()) {
249 0 : if (it.second.hasFlag(db::Flags::ForceExclude)) {
250 0 : ret.erase(it.second.getName());
251 : }
252 : }
253 : }
254 3625 : ret.setInteger(id, "__oid");
255 : } else {
256 0 : ret = Value();
257 0 : return;
258 : }
259 : } else {
260 0 : val.finalize();
261 0 : if (performQuery(query) != 1) {
262 0 : ret = Value();
263 0 : return;
264 : }
265 : }
266 :
267 3625 : if (id > 0) {
268 3625 : performPostUpdate(worker.transaction(), query, scheme, ret, id, postUpdate, false);
269 : }
270 3625 : }, &queryStorage);
271 3625 : queryStorage.clear();
272 :
273 7250 : return ret;
274 3625 : };
275 :
276 3650 : if (Handle_hasPostUpdate(inputFields, inputRows)) {
277 : // process one-by-one
278 300 : Value ret;
279 300 : for (auto &it : inputRows) {
280 300 : if (!multiCreate) {
281 300 : ret = perform(it);
282 : } else {
283 0 : ret.addValue(perform(it));
284 : }
285 300 : return ret;
286 : }
287 300 : } else {
288 3350 : if (!multiCreate) {
289 3325 : return perform(inputRows.front());
290 : }
291 :
292 25 : Value ret;
293 25 : makeQuery([&, this] (SqlQuery &query) {
294 25 : auto ins = query.insert(scheme.getName());
295 100 : for (auto &it : inputFields) {
296 75 : ins.field(it.field->getName());
297 : }
298 :
299 25 : auto val = ins.values();
300 75 : for (auto &row : inputRows) {
301 50 : auto &r = ret.emplace();
302 50 : bindRow(r, val, row);
303 50 : val = val.next();
304 : }
305 :
306 25 : auto &conflicts = worker.getConflicts();
307 25 : for (auto &it : conflicts) {
308 0 : if (it.second.isDoNothing()) {
309 0 : val.onConflict(it.first->getName()).doNothing();
310 : } else {
311 0 : auto c = val.onConflict(it.first->getName()).doUpdate();
312 0 : for (auto &iit : inputFields) {
313 0 : if ((it.second.mask.empty() || std::find(it.second.mask.begin(), it.second.mask.end(), iit.field) != it.second.mask.end())) {
314 0 : c.excluded(iit.field->getName());
315 : }
316 : }
317 :
318 0 : if (it.second.hasCondition()) {
319 0 : c.where().parenthesis(db::Operator::And, [&] (SqlQuery::WhereBegin &wh) {
320 0 : SqlQuery::WhereContinue iw(wh.query, wh.state);
321 0 : query.writeWhereCond(iw, db::Operator::And, worker.scheme(), it.second.condition);
322 0 : });
323 : }
324 : }
325 : }
326 :
327 25 : val.returning().field(SqlQuery::Field("__oid").as("id")).finalize();
328 25 : selectQuery(query, [&, this] (Result &res) {
329 25 : size_t i = 0;
330 75 : for (auto it : res) {
331 50 : ret.getValue(i).setInteger(it.toInteger(0), "__oid");
332 50 : ++ i;
333 : }
334 :
335 75 : for (auto &iit : ret.asArray()) {
336 50 : if (worker.shouldIncludeNone() && worker.scheme().hasForceExclude()) {
337 0 : for (auto &it : worker.scheme().getFields()) {
338 0 : if (it.second.hasFlag(db::Flags::ForceExclude)) {
339 0 : iit.erase(it.second.getName());
340 : }
341 : }
342 : }
343 : }
344 25 : return true;
345 : });
346 25 : }, &queryStorage);
347 :
348 25 : return ret;
349 25 : }
350 0 : return Value();
351 3650 : }
352 :
353 2550 : Value SqlHandle::save(Worker &worker, uint64_t oid, const Value &data, const Vector<InputField> &inputFields, InputRow &inputRow) {
354 2550 : if ((!data.isDictionary() && !data.empty()) || inputFields.empty() || inputRow.values.empty()) {
355 0 : return Value();
356 : }
357 :
358 2550 : auto queryStorage = _driver->makeQueryStorage(worker.scheme().getName());
359 :
360 2550 : Value ret(data);
361 2550 : auto &scheme = worker.scheme();
362 :
363 2550 : Value postUpdate(Handle_preparePostUpdate(inputFields, inputRow));
364 :
365 2550 : makeQuery([&, this] (SqlQuery &query) {
366 2550 : auto upd = query.update(scheme.getName());
367 :
368 8175 : for (size_t idx = 0; idx < inputFields.size(); ++ idx) {
369 5625 : auto &f = inputFields[idx];
370 5625 : auto &v = inputRow.values[idx];
371 :
372 5625 : switch (f.field->getType()) {
373 25 : case Type::View:
374 : case Type::Set:
375 : case Type::Array:
376 : case Type::Virtual:
377 25 : break;
378 125 : case Type::Object:
379 125 : if (v.hasValue() && v.value.isDictionary() && v.value.isInteger("__oid")) {
380 0 : upd.set(f.field->getName(), v.value.getInteger("__oid"));
381 125 : } else if (v.value.isInteger()) {
382 75 : upd.set(f.field->getName(), v.value.getInteger());
383 : }
384 125 : break;
385 5475 : default:
386 5475 : switch (v.type) {
387 5375 : case InputValue::Type::Value: {
388 5375 : ret.setValue(v.value, f.field->getName());
389 5375 : upd.set(f.field->getName(), db::Binder::DataField{f.field, v.value, f.field->isDataLayout(), f.field->hasFlag(db::Flags::Compressed)});
390 5375 : break;
391 : }
392 100 : case InputValue::Type::TSV:
393 100 : upd.set(f.field->getName(), db::Binder::FullTextField{f.field, v.tsv});
394 100 : break;
395 0 : case InputValue::Type::File:
396 : case InputValue::Type::None:
397 0 : break;
398 : }
399 5475 : break;
400 : }
401 : }
402 :
403 2550 : auto q = upd.where("__oid", Comparation::Equal, oid);
404 2550 : auto &cond = worker.getConditions();
405 2550 : if (!cond.empty()) {
406 0 : q.parenthesis(db::Operator::And, [&] (SqlQuery::WhereBegin &wh) {
407 0 : SqlQuery::WhereContinue iw(wh.query, wh.state);
408 0 : for (auto &it : cond) {
409 0 : query.writeWhereCond(iw, db::Operator::And, worker.scheme(), it);
410 : }
411 0 : });
412 : }
413 :
414 5100 : FieldResolver resv(worker.scheme(), worker);
415 2550 : if (!worker.shouldIncludeNone()) {
416 450 : auto returning = q.returning();
417 1100 : for (auto &it : data.asDict()) {
418 650 : resv.include(it.first);
419 : }
420 450 : resv.readFields([&] (const StringView &name, const Field *) {
421 450 : returning.field(name);
422 450 : });
423 450 : q.finalize();
424 : } else {
425 2100 : q.returning().field("__oid").finalize();
426 : }
427 :
428 5100 : auto retVal = selectValueQuery(worker.scheme(), query, resv.getVirtuals());
429 2550 : if (retVal.isArray() && retVal.size() == 1) {
430 2550 : Value obj = std::move(retVal.getValue(0));
431 2550 : int64_t id = obj.getInteger("__oid");
432 2550 : if (id > 0) {
433 2550 : performPostUpdate(worker.transaction(), query, scheme, obj, id, postUpdate, false);
434 : }
435 2550 : ret = std::move(obj);
436 2550 : } else if (!cond.empty() && isSuccess()) {
437 0 : ret = Value({ stappler::pair("__oid", Value(oid)) });
438 : } else {
439 0 : _driver->getApplicationInterface()->debug("Storage", "Fail to update object", Value({
440 0 : std::make_pair("id", Value(oid)),
441 0 : std::make_pair("query", Value(query.getStream().weak())),
442 0 : std::make_pair("data", Value(data)),
443 0 : std::make_pair("ret", Value(ret)),
444 0 : }));
445 : }
446 2550 : }, &queryStorage);
447 2550 : return ret;
448 2550 : }
449 :
450 275 : bool SqlHandle::remove(Worker &worker, uint64_t oid) {
451 275 : auto &scheme = worker.scheme();
452 :
453 275 : auto queryStorage = _driver->makeQueryStorage(worker.scheme().getName());
454 :
455 275 : bool ret = false;
456 275 : makeQuery([&, this] (SqlQuery &query) {
457 275 : auto q = query.remove(scheme.getName())
458 275 : .where("__oid", Comparation::Equal, oid);
459 275 : q.finalize();
460 275 : if (performQuery(query) == 1) { // one row affected
461 275 : ret = true;
462 : }
463 275 : }, &queryStorage);
464 275 : return ret;
465 275 : }
466 :
467 375 : size_t SqlHandle::count(Worker &worker, const db::Query &q) {
468 375 : auto &scheme = worker.scheme();
469 :
470 375 : auto queryStorage = _driver->makeQueryStorage(worker.scheme().getName());
471 :
472 375 : size_t ret = 0;
473 375 : makeQuery([&, this] (SqlQuery &query) {
474 375 : auto ordField = q.getQueryField();
475 375 : if (ordField.empty()) {
476 375 : auto f = query.select().count().from(scheme.getName());
477 :
478 375 : SqlQuery_makeCustomFrom(_driver, query, f, q, scheme);
479 :
480 375 : if (!q.empty()) {
481 200 : auto w = f.where();
482 200 : query.writeWhere(w, Operator::And, scheme, q);
483 : }
484 :
485 375 : query.finalize();
486 750 : selectQuery(query, [&] (Result &res) {
487 375 : if (!res.empty()) {
488 750 : ret = res.current().toInteger(0);
489 375 : return true;
490 : }
491 0 : return false;
492 : });
493 0 : } else if (auto f = scheme.getField(ordField)) {
494 0 : switch (f->getType()) {
495 0 : case Type::Set:
496 0 : ret = getSetCount(worker, query, q.getQueryId(), *f, q);
497 0 : break;
498 0 : case Type::View:
499 0 : ret = getViewCount(worker, query, q.getQueryId(), *f, q);
500 0 : break;
501 0 : default:
502 0 : break;
503 : }
504 : }
505 375 : }, &queryStorage);
506 375 : return ret;
507 375 : }
508 :
509 6175 : void SqlHandle::performPostUpdate(const db::Transaction &t, SqlQuery &query, const Scheme &s, Value &data, int64_t id, const Value &upd, bool clear) {
510 6175 : query.clear();
511 :
512 0 : auto makeObject = [&] (const Field &field, const Value &obj) {
513 0 : int64_t targetId = 0;
514 0 : if (obj.isDictionary()) {
515 0 : Value val(std::move(obj));
516 0 : if (auto scheme = field.getForeignScheme()) {
517 0 : if (auto link = s.getForeignLink(field)) {
518 0 : val.setInteger(id, link->getName().str<Interface>());
519 : }
520 0 : val = Worker(*scheme, t).create(val);
521 0 : if (val.isInteger("__oid")) {
522 0 : targetId = val.getInteger("__oid");
523 : }
524 : }
525 0 : }
526 :
527 0 : if (targetId) {
528 0 : Worker w(s, t);
529 0 : w.includeNone();
530 0 : Value patch{ stappler::pair(field.getName().str<Interface>(), Value(targetId)) };
531 0 : t.patch(w, id, patch);
532 0 : data.setInteger(targetId, field.getName().str<Interface>());
533 0 : }
534 0 : };
535 :
536 0 : auto makeSet = [&, this] (const Field &field, const Value &obj) {
537 0 : auto f = field.getSlot<db::FieldObject>();
538 0 : auto scheme = field.getForeignScheme();
539 :
540 0 : if (f && scheme && obj.isArray()) {
541 0 : Value ret;
542 0 : Vector<int64_t> toAdd;
543 :
544 0 : if (clear && obj) {
545 0 : Worker(s, t).clearField(id, field);
546 : }
547 :
548 0 : for (auto &arr_it : obj.asArray()) {
549 0 : if (arr_it.isDictionary()) {
550 0 : Value val(std::move(arr_it));
551 0 : if (auto link = s.getForeignLink(field)) {
552 0 : val.setInteger(id, link->getName().str<Interface>());
553 : }
554 0 : val = Worker(*scheme, t).create(val);
555 0 : if (val) {
556 0 : ret.addValue(std::move(val));
557 : }
558 0 : } else {
559 0 : if (auto tmp = arr_it.asInteger()) {
560 0 : if (field.isReference()) {
561 0 : toAdd.emplace_back(tmp);
562 0 : } else if (auto link = s.getForeignLink(field)) {
563 0 : if (auto val = Worker(*scheme, t).update(tmp, Value{stappler::pair(link->getName().str<Interface>(), Value(id))})) {
564 0 : ret.addValue(std::move(val));
565 0 : }
566 : }
567 : }
568 : }
569 : }
570 :
571 0 : if (!toAdd.empty()) {
572 0 : if (field.isReference()) {
573 0 : query.clear();
574 0 : if (insertIntoRefSet(query, s, id, field, toAdd)) {
575 0 : for (auto &add_it : toAdd) {
576 0 : ret.addInteger(add_it);
577 : }
578 : }
579 : }
580 : }
581 0 : data.setValue(std::move(ret), field.getName().str<Interface>());
582 0 : }
583 0 : };
584 :
585 6175 : const Map<String, Field> &fields = s.getFields();
586 6225 : for (auto &it : upd.asDict()) {
587 50 : auto f_it = fields.find(it.first);
588 50 : if (f_it != fields.end()) {
589 50 : if (f_it->second.getType() == db::Type::Object) {
590 0 : makeObject(f_it->second, it.second);
591 50 : } else if (f_it->second.getType() == db::Type::Set) {
592 0 : makeSet(f_it->second, it.second);
593 50 : } else if (f_it->second.getType() == db::Type::Array) {
594 50 : if (clear && it.second) {
595 0 : Worker(s, t).clearField(id, f_it->second);
596 : }
597 50 : query.clear();
598 50 : auto tmp = it.second;
599 50 : if (insertIntoArray(query, s, id, f_it->second, tmp)) {
600 50 : data.setValue(tmp, f_it->second.getName());
601 : }
602 50 : }
603 : }
604 : }
605 6175 : }
606 :
607 775 : Vector<int64_t> SqlHandle::performQueryListForIds(const QueryList &list, size_t count) {
608 775 : Vector<int64_t> ret;
609 :
610 775 : auto queryStorage = _driver->makeQueryStorage(list.getScheme()->getName());
611 :
612 775 : makeQuery([&, this] (SqlQuery &query) {
613 775 : query.writeQueryList(list, true, count);
614 775 : query.finalize();
615 :
616 1550 : selectQuery(query, [&] (Result &res) {
617 775 : for (auto it : res) {
618 1525 : ret.push_back(it.toInteger(0));
619 750 : return true;
620 : }
621 25 : return false;
622 : });
623 775 : }, &queryStorage);
624 :
625 1550 : return ret;
626 775 : }
627 :
628 1125 : Value SqlHandle::performQueryList(const QueryList &list, size_t count, bool forUpdate) {
629 1125 : Value ret;
630 :
631 1125 : auto queryStorage = _driver->makeQueryStorage(list.getScheme()->getName());
632 :
633 1125 : makeQuery([&, this] (SqlQuery &query) {
634 1125 : FieldResolver resv(*list.getScheme(), list.getTopQuery());
635 1125 : query.writeQueryList(list, false, count);
636 1125 : if (forUpdate) {
637 0 : query << "FOR UPDATE";
638 : }
639 1125 : query.finalize();
640 :
641 1125 : ret = selectValueQuery(*list.getScheme(), query, resv.getVirtuals());
642 1125 : }, &queryStorage);
643 2250 : return ret;
644 1125 : }
645 :
646 200 : bool SqlHandle::removeFromView(const db::FieldView &view, const Scheme *scheme, uint64_t oid) {
647 200 : bool ret = false;
648 200 : if (scheme) {
649 200 : String name = toString(scheme->getName(), "_f_", view.name, "_view");
650 :
651 200 : auto queryStorage = _driver->makeQueryStorage(view.owner->getName());
652 :
653 200 : makeQuery([&, this] (SqlQuery &query) {
654 200 : query << "DELETE FROM " << name << " WHERE \"" << view.scheme->getName() << "_id\"=" << oid << ";";
655 200 : ret = performQuery(query) != stappler::maxOf<size_t>();
656 200 : }, &queryStorage);
657 200 : }
658 200 : return ret;
659 : }
660 :
661 125 : bool SqlHandle::addToView(const db::FieldView &view, const Scheme *scheme, uint64_t tag, const Value &data) {
662 125 : bool ret = false;
663 125 : if (scheme) {
664 125 : String name = toString(scheme->getName(), "_f_", view.name, "_view");
665 :
666 125 : auto queryStorage = _driver->makeQueryStorage(view.owner->getName());
667 :
668 125 : makeQuery([&, this] (SqlQuery &query) {
669 125 : auto ins = query.insert(name);
670 375 : for (auto &it : data.asDict()) {
671 250 : ins.field(it.first);
672 : }
673 :
674 125 : auto val = ins.values();
675 375 : for (auto &it : data.asDict()) {
676 250 : val.value(db::Binder::DataField{nullptr, it.second, false});
677 : }
678 :
679 125 : val.finalize();
680 125 : ret = performQuery(query) != stappler::maxOf<size_t>();
681 125 : }, &queryStorage);
682 125 : }
683 125 : return ret;
684 : }
685 :
686 0 : Vector<int64_t> SqlHandle::getReferenceParents(const Scheme &objectScheme, uint64_t oid, const Scheme *parentScheme, const Field *parentField) {
687 0 : Vector<int64_t> vec;
688 0 : if (parentField->isReference() && parentField->getType() == db::Type::Set) {
689 0 : auto schemeName = toString(parentScheme->getName(), "_f_", parentField->getName());
690 0 : auto queryStorage = _driver->makeQueryStorage(schemeName);
691 0 : makeQuery([&, this] (SqlQuery &q) {
692 0 : q.select(toString(parentScheme->getName(), "_id"))
693 0 : .from(schemeName)
694 0 : .where(toString(objectScheme.getName(), "_id"), Comparation::Equal, oid);
695 :
696 0 : selectQuery(q, [&] (Result &res) {
697 0 : vec.reserve(res.getRowsHint());
698 0 : for (auto it : res) {
699 0 : if (auto id = it.toInteger(0)) {
700 0 : vec.emplace_back(id);
701 : }
702 : }
703 0 : return true;
704 : });
705 0 : }, &queryStorage);
706 0 : }
707 :
708 0 : return vec;
709 0 : }
710 :
711 : }
|