LCOV - code coverage report
Current view: top level - core/db/sqlite - SPSqliteModuleUnwrap.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 68 94 72.3 %
Date: 2024-05-12 00:16:13 Functions: 9 10 90.0 %

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 2024 Stappler LLC <admin@stappler.dev>
       3             : 
       4             :  Permission is hereby granted, free of charge, to any person obtaining a copy
       5             :  of this software and associated documentation files (the "Software"), to deal
       6             :  in the Software without restriction, including without limitation the rights
       7             :  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       8             :  copies of the Software, and to permit persons to whom the Software is
       9             :  furnished to do so, subject to the following conditions:
      10             : 
      11             :  The above copyright notice and this permission notice shall be included in
      12             :  all copies or substantial portions of the Software.
      13             : 
      14             :  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      17             :  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18             :  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      19             :  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      20             :  THE SOFTWARE.
      21             :  **/
      22             : 
      23             : #include "SPSqliteDriver.h"
      24             : #include "sqlite3.h"
      25             : 
      26             : namespace STAPPLER_VERSIONIZED stappler::db::sqlite {
      27             : 
      28             : static constexpr auto UNWRAP_VALUE = 0;
      29             : static constexpr auto UNWRAP_INPUT = 0;
      30             : 
      31             : struct UnwrapCursor {
      32             :         sqlite3_vtab_cursor base;
      33             :         BytesView origValue;
      34             :         BytesView currentValue;
      35             :         Value value;
      36             :         size_t current = 0;
      37             : };
      38             : 
      39             : static sqlite3_module s_UnwrapModule = {
      40             :         .iVersion = 4,
      41             :         .xCreate = nullptr, // [] (sqlite3*, void *pAux, int argc, const char *const* argv, sqlite3_vtab **ppVTab, char**) -> int { },
      42          50 :         .xConnect = [] (sqlite3 *db, void *pAux, int argc, const char * const* argv, sqlite3_vtab **ppVTab, char**) -> int {
      43             :                 sqlite3_vtab *pNew;
      44             :                 int rc;
      45             : 
      46          50 :                 rc = sqlite3_declare_vtab(db, "CREATE TABLE x(__unwrap_value, input HIDDEN)");
      47          50 :                 if (rc == SQLITE_OK) {
      48          50 :                         pNew = *ppVTab = (sqlite3_vtab *)sqlite3_malloc(sizeof(*pNew));
      49          50 :                         if (pNew == 0) {
      50           0 :                                 return SQLITE_NOMEM;
      51             :                         }
      52          50 :                         memset(pNew, 0, sizeof(*pNew));
      53             :                 }
      54          50 :                 return rc;
      55             :         },
      56         350 :         .xBestIndex = [] (sqlite3_vtab *pVTab, sqlite3_index_info *pIdxInfo) -> int {
      57         350 :                 int unusableMask = 0;
      58         350 :                 int inputIndex = -1;
      59         350 :                 int idxMask = 0;
      60         350 :                 auto pConstraint = pIdxInfo->aConstraint;
      61         950 :                 for (int i = 0; i < pIdxInfo->nConstraint; i++, pConstraint++) {
      62             :                         int iCol;
      63             :                         int iMask;
      64         600 :                         if (pConstraint->iColumn < UNWRAP_INPUT)
      65           0 :                                 continue;
      66         600 :                         iCol = pConstraint->iColumn - UNWRAP_INPUT;
      67         600 :                         iMask = 1 << iCol;
      68         600 :                         if (pConstraint->usable == 0) {
      69         175 :                                 unusableMask |= iMask;
      70         425 :                         } else if (pConstraint->op == SQLITE_INDEX_CONSTRAINT_EQ) {
      71         425 :                                 inputIndex = i;
      72         425 :                                 idxMask |= iMask;
      73             :                         }
      74             :                 }
      75             : 
      76         350 :                 if (pIdxInfo->nOrderBy > 0 && pIdxInfo->aOrderBy[0].iColumn < 0 && pIdxInfo->aOrderBy[0].desc == 0) {
      77           0 :                         pIdxInfo->orderByConsumed = 1;
      78             :                 }
      79             : 
      80         350 :                 if ((unusableMask & ~idxMask) != 0) {
      81             :                         /* If there are any unusable constraints, then reject
      82             :                          ** this entire plan */
      83         175 :                         return SQLITE_CONSTRAINT;
      84             :                 }
      85             : 
      86         175 :                 if (inputIndex < 0) {
      87             :                         /* No input */
      88           0 :                         pIdxInfo->idxNum = 0;
      89             :                 } else {
      90         175 :                         pIdxInfo->estimatedCost = 1.0;
      91         175 :                         pIdxInfo->aConstraintUsage[inputIndex].argvIndex = 1;
      92         175 :                         pIdxInfo->aConstraintUsage[inputIndex].omit = 1;
      93         175 :                         pIdxInfo->idxNum = 1; /* Only JSON supplied.  Plan 1 */
      94             :                 }
      95         175 :                 return SQLITE_OK;
      96             :         },
      97          50 :         .xDisconnect = [] (sqlite3_vtab *pVTab) -> int {
      98          50 :                 sqlite3_free(pVTab);
      99          50 :                 return SQLITE_OK;
     100             :         },
     101             :         .xDestroy = nullptr, // [] (sqlite3_vtab *pVTab) -> int { },
     102         175 :         .xOpen = [] (sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor) -> int {
     103             :                 UnwrapCursor *pCur;
     104         175 :                 pCur = (UnwrapCursor *)sqlite3_malloc(sizeof(*pCur));
     105         175 :                 if (pCur == 0) {
     106           0 :                         return SQLITE_NOMEM;
     107             :                 }
     108         175 :                 memset(pCur, 0, sizeof(*pCur));
     109         175 :                 *ppCursor = &pCur->base;
     110         175 :                 return SQLITE_OK;
     111             :         },
     112         175 :         .xClose = [] (sqlite3_vtab_cursor *cur) -> int {
     113         175 :                 UnwrapCursor *p = (UnwrapCursor*)cur;
     114         175 :                 p->~UnwrapCursor();
     115         175 :                 sqlite3_free(cur);
     116         175 :                 return SQLITE_OK;
     117             :         },
     118         225 :         .xFilter = [] (sqlite3_vtab_cursor *cur, int idxNum, const char *idxStr, int argc, sqlite3_value **argv) -> int {
     119         225 :                 UnwrapCursor *p = (UnwrapCursor*)cur;
     120         225 :                 p->origValue = p->currentValue = BytesView((const uint8_t *)sqlite3_value_blob(argv[0]), sqlite3_value_bytes(argv[0]));
     121         225 :                 p->value = data::read<Interface>(p->origValue);
     122         225 :                 p->current = 0;
     123         225 :                 if (p->value.isArray() || p->value.empty()) {
     124         225 :                         return SQLITE_OK;
     125             :                 }
     126           0 :                 p->value = Value();
     127           0 :                 return SQLITE_MISMATCH;
     128             :         },
     129         400 :         .xNext = [] (sqlite3_vtab_cursor *cur) -> int {
     130         400 :                 UnwrapCursor *p = (UnwrapCursor*)cur;
     131         400 :                 ++ p->current;
     132         400 :                 return SQLITE_OK;
     133             :         },
     134         625 :         .xEof = [] (sqlite3_vtab_cursor *cur) -> int {
     135         625 :                 UnwrapCursor *p = (UnwrapCursor*)cur;
     136         625 :                 if (p->value.empty() || p->current == p->value.size()) {
     137         200 :                         return 1;
     138             :                 }
     139         425 :                 return 0;
     140             :         },
     141         500 :         .xColumn = [] (sqlite3_vtab_cursor *cur, sqlite3_context *db, int col) -> int {
     142         500 :                 UnwrapCursor *p = (UnwrapCursor*)cur;
     143             : 
     144         500 :                 auto &val = p->value.getValue(p->current);
     145         500 :                 switch (val.getType()) {
     146           0 :                 case Value::Type::INTEGER:
     147           0 :                         sqlite3_result_int64(db, val.getInteger());
     148           0 :                         break;
     149           0 :                 case Value::Type::DOUBLE:
     150           0 :                         sqlite3_result_double(db, val.getDouble());
     151           0 :                         break;
     152           0 :                 case Value::Type::BOOLEAN:
     153           0 :                         sqlite3_result_int(db, val.getBool() ? 1 : 0);
     154           0 :                         break;
     155         500 :                 case Value::Type::CHARSTRING:
     156         500 :                         sqlite3_result_text64(db, val.getString().data(), val.getString().size(), nullptr, SQLITE_UTF8);
     157         500 :                         break;
     158           0 :                 case Value::Type::BYTESTRING:
     159           0 :                         sqlite3_result_blob64(db, val.getBytes().data(), val.getBytes().size(), nullptr);
     160           0 :                         break;
     161           0 :                 default:
     162           0 :                     sqlite3_result_null(db);
     163           0 :                         break;
     164             :                 }
     165         500 :                 return SQLITE_OK;
     166             :         },
     167           0 :         .xRowid = [] (sqlite3_vtab_cursor *cur, sqlite3_int64 *pRowid) -> int {
     168           0 :                 UnwrapCursor *p = (UnwrapCursor*) cur;
     169           0 :                 *pRowid = p->current;
     170           0 :                 return SQLITE_OK;
     171             :         },
     172             :         .xUpdate = nullptr, // [] (sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *) -> int { },
     173             :         .xBegin = nullptr, // [] (sqlite3_vtab *pVTab) -> int { },
     174             :         .xSync = nullptr, // [] (sqlite3_vtab *pVTab) -> int { },
     175             :         .xCommit = nullptr, // [] (sqlite3_vtab *pVTab) -> int { },
     176             :         .xRollback = nullptr, // [] (sqlite3_vtab *pVTab) -> int { },
     177             :         .xFindFunction = nullptr, // [] (sqlite3_vtab *pVtab, int nArg, const char *zName,
     178             :                         // void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), void **ppArg) -> int { },
     179             :         .xRename = nullptr, // [] (sqlite3_vtab *pVtab, const char *zNew) -> int { },
     180             :           /* The methods above are in version 1 of the sqlite_module object. Those
     181             :           ** below are for version 2 and greater. */
     182             :         .xSavepoint = nullptr, // [] (sqlite3_vtab *pVTab, int) -> int { },
     183             :         .xRelease = nullptr, // [] (sqlite3_vtab *pVTab, int) -> int { },
     184             :         .xRollbackTo = nullptr, // [] (sqlite3_vtab *pVTab, int) -> int { },
     185             :           /* The methods above are in versions 1 and 2 of the sqlite_module object.
     186             :           ** Those below are for version 3 and greater. */
     187             :         .xShadowName = nullptr, // [] (const char*) -> int { }
     188             : };
     189             : 
     190             : }

Generated by: LCOV version 1.14