LCOV - code coverage report
Current view: top level - home/snapwebsites/snapcpp/snapwebsites/snapdatabase/snapdatabase/data - script.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 13 195 6.7 %
Date: 2019-12-15 17:13:15 Functions: 3 4 75.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2019  Made to Order Software Corp.  All Rights Reserved
       2             : //
       3             : // https://snapwebsites.org/project/snapdatabase
       4             : // contact@m2osw.com
       5             : //
       6             : // This program is free software; you can redistribute it and/or modify
       7             : // it under the terms of the GNU General Public License as published by
       8             : // the Free Software Foundation; either version 2 of the License, or
       9             : // (at your option) any later version.
      10             : //
      11             : // This program is distributed in the hope that it will be useful,
      12             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             : // GNU General Public License for more details.
      15             : //
      16             : // You should have received a copy of the GNU General Public License along
      17             : // with this program; if not, write to the Free Software Foundation, Inc.,
      18             : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      19             : 
      20             : 
      21             : /** \file
      22             :  * \brief Script handling implementation.
      23             :  *
      24             :  * In various places we allow scripts to be run. Scripts are used to filter
      25             :  * the data and generate keys of secondary indexes.
      26             :  */
      27             : 
      28             : // self
      29             : //
      30             : #include    "snapdatabase/data/script.h"
      31             : 
      32             : 
      33             : // snapwebsites lib (TODO: remove dependency--especially because we do not want Qt in snapdatabase!)
      34             : //
      35             : #include    <snapwebsites/snap_expr.h>
      36             : 
      37             : 
      38             : // snaplogger lib
      39             : //
      40             : #include    <snaplogger/message.h>
      41             : 
      42             : 
      43             : // last include
      44             : //
      45             : #include    <snapdev/poison.h>
      46             : 
      47             : 
      48             : 
      49             : namespace snapdatabase
      50             : {
      51             : 
      52             : 
      53             : 
      54           1 : buffer_t compile_script(std::string const & script)
      55             : {
      56           2 :     snap::snap_expr::expr e;
      57           1 :     if(!e.compile(QString::fromUtf8(script.c_str())))
      58             :     {
      59           0 :         SNAP_LOG_WARNING
      60           0 :             << "Invalid script \""
      61             :             << script
      62             :             << "\". We were not able to compile it."
      63             :             << SNAP_LOG_SEND;
      64           0 :         return buffer_t();
      65             :     }
      66           2 :     QByteArray buf(e.serialize());
      67             : 
      68             :     // convert the QByteArray to a buffer_t
      69             :     //
      70           1 :     uint32_t size(buf.size());
      71           2 :     buffer_t result;
      72           1 :     result.reserve(size + 8);       // header is "SSX1" + uint32_t size in little endian
      73           1 :     char const * magic = "SSX1";
      74           1 :     result.insert(result.end(), magic, magic + 4);
      75           1 :     result.insert(result.end(), reinterpret_cast<uint8_t *>(&size), reinterpret_cast<uint8_t *>(&size + 1));
      76           1 :     result.insert(result.end(), reinterpret_cast<uint8_t *>(buf.data()), reinterpret_cast<uint8_t *>(buf.data()) + size);
      77             : 
      78           1 :     return result;
      79             : }
      80             : 
      81             : 
      82           0 : buffer_t execute_script(buffer_t compiled_script, row::pointer_t row)
      83             : {
      84           0 :     buffer_t result;
      85             : 
      86           0 :     int size(compiled_script.size());
      87           0 :     if(size < 8)
      88             :     {
      89           0 :         SNAP_LOG_WARNING
      90           0 :             << "A script buffer has to be at least 8 bytes."
      91             :             << SNAP_LOG_SEND;
      92           0 :         return result;
      93             :     }
      94           0 :     size -= 8;
      95             : 
      96           0 :     char const * input(reinterpret_cast<char const *>(compiled_script.data()));
      97           0 :     if(input[0] != 'S'
      98           0 :     || input[1] != 'S'
      99           0 :     || input[2] != 'X'
     100           0 :     || input[3] != '1')
     101             :     {
     102           0 :         SNAP_LOG_WARNING
     103           0 :             << "Script type ('"
     104           0 :             << input[0]
     105           0 :             << input[1]
     106           0 :             << input[2]
     107           0 :             << input[3]
     108             :             << "') not currently supported."
     109             :             << SNAP_LOG_SEND;
     110           0 :         return result;
     111             :     }
     112           0 :     input += 4;
     113             : 
     114           0 :     int const expected_size((input[0] <<  0)
     115           0 :                           | (input[1] <<  8)
     116           0 :                           | (input[2] << 16)
     117           0 :                           | (input[3] << 24));
     118           0 :     if(expected_size != size)
     119             :     {
     120           0 :         SNAP_LOG_WARNING
     121           0 :             << "Unexpected script size (got "
     122             :             << size
     123           0 :             << ", expected "
     124             :             << expected_size
     125             :             << "')."
     126             :             << SNAP_LOG_SEND;
     127           0 :         return result;
     128             :     }
     129           0 :     input += 4;
     130             : 
     131             :     try
     132             :     {
     133           0 :         QByteArray buf(input, size);
     134             : 
     135           0 :         snap::snap_expr::expr e;
     136           0 :         e.unserialize(buf);
     137             : 
     138           0 :         snap::snap_expr::variable_t return_value;
     139           0 :         snap::snap_expr::functions_t functions;
     140             : 
     141             :         // TODO: transform the entire row in script variables
     142           0 :         snap::snap_expr::variable_t::variable_map_t variables;
     143           0 :         cell::map_t cells(row->cells());
     144           0 :         for(auto const & c : cells)
     145             :         {
     146           0 :             schema_column::pointer_t schema(c.second->schema());
     147           0 :             snap::snap_expr::variable_t v(QString::fromUtf8(schema->name().c_str()));
     148           0 :             switch(schema->type())
     149             :             {
     150           0 :             case struct_type_t::STRUCT_TYPE_VOID:
     151           0 :                 v.set_value();
     152           0 :                 break;
     153             : 
     154           0 :             case struct_type_t::STRUCT_TYPE_BITS8:
     155             :             case struct_type_t::STRUCT_TYPE_UINT8:
     156           0 :                 v.set_value(c.second->get_uint8());
     157           0 :                 break;
     158             : 
     159           0 :             case struct_type_t::STRUCT_TYPE_INT8:
     160           0 :                 v.set_value(c.second->get_int8());
     161           0 :                 break;
     162             : 
     163           0 :             case struct_type_t::STRUCT_TYPE_BITS16:
     164             :             case struct_type_t::STRUCT_TYPE_UINT16:
     165           0 :                 v.set_value(c.second->get_uint16());
     166           0 :                 break;
     167             : 
     168           0 :             case struct_type_t::STRUCT_TYPE_INT16:
     169           0 :                 v.set_value(c.second->get_int16());
     170           0 :                 break;
     171             : 
     172           0 :             case struct_type_t::STRUCT_TYPE_BITS32:
     173             :             case struct_type_t::STRUCT_TYPE_UINT32:
     174             :             case struct_type_t::STRUCT_TYPE_VERSION:
     175           0 :                 v.set_value(c.second->get_uint32());
     176           0 :                 break;
     177             : 
     178           0 :             case struct_type_t::STRUCT_TYPE_INT32:
     179           0 :                 v.set_value(c.second->get_int32());
     180           0 :                 break;
     181             : 
     182           0 :             case struct_type_t::STRUCT_TYPE_BITS64:
     183             :             case struct_type_t::STRUCT_TYPE_UINT64:
     184             :             case struct_type_t::STRUCT_TYPE_REFERENCE:
     185             :             case struct_type_t::STRUCT_TYPE_OID:
     186             :             case struct_type_t::STRUCT_TYPE_TIME:
     187             :             case struct_type_t::STRUCT_TYPE_MSTIME:
     188             :             case struct_type_t::STRUCT_TYPE_USTIME:
     189           0 :                 v.set_value(c.second->get_uint64());
     190           0 :                 break;
     191             : 
     192           0 :             case struct_type_t::STRUCT_TYPE_INT64:
     193           0 :                 v.set_value(c.second->get_int64());
     194           0 :                 break;
     195             : 
     196           0 :             case struct_type_t::STRUCT_TYPE_BITS128:
     197             :             case struct_type_t::STRUCT_TYPE_UINT128:
     198             :                 {
     199           0 :                     uint512_t value(c.second->get_uint128());
     200           0 :                     QByteArray data(reinterpret_cast<char const *>(value.f_value), sizeof(uint64_t) * 2);
     201           0 :                     v.set_value(data);
     202             :                 }
     203           0 :                 break;
     204             : 
     205           0 :             case struct_type_t::STRUCT_TYPE_INT128:
     206             :                 {
     207           0 :                     uint512_t value(c.second->get_int128());
     208           0 :                     QByteArray data(reinterpret_cast<char const *>(value.f_value), sizeof(uint64_t) * 2);
     209           0 :                     v.set_value(data);
     210             :                 }
     211           0 :                 break;
     212             : 
     213           0 :             case struct_type_t::STRUCT_TYPE_BITS256:
     214             :             case struct_type_t::STRUCT_TYPE_UINT256:
     215             :                 {
     216           0 :                     uint512_t value(c.second->get_uint256());
     217           0 :                     QByteArray data(reinterpret_cast<char const *>(value.f_value), sizeof(uint64_t) * 4);
     218           0 :                     v.set_value(data);
     219             :                 }
     220           0 :                 break;
     221             : 
     222           0 :             case struct_type_t::STRUCT_TYPE_INT256:
     223             :                 {
     224           0 :                     uint512_t value(c.second->get_int256());
     225           0 :                     QByteArray data(reinterpret_cast<char const *>(value.f_value), sizeof(uint64_t) * 4);
     226           0 :                     v.set_value(data);
     227             :                 }
     228           0 :                 break;
     229             : 
     230           0 :             case struct_type_t::STRUCT_TYPE_BITS512:
     231             :             case struct_type_t::STRUCT_TYPE_UINT512:
     232             :                 {
     233           0 :                     uint512_t value(c.second->get_uint512());
     234           0 :                     QByteArray data(reinterpret_cast<char const *>(value.f_value), sizeof(uint64_t) * 8);
     235           0 :                     v.set_value(data);
     236             :                 }
     237           0 :                 break;
     238             : 
     239           0 :             case struct_type_t::STRUCT_TYPE_INT512:
     240             :                 {
     241           0 :                     uint512_t value(c.second->get_int512());
     242           0 :                     QByteArray data(reinterpret_cast<char const *>(value.f_value), sizeof(uint64_t) * 8);
     243           0 :                     v.set_value(data);
     244             :                 }
     245           0 :                 break;
     246             : 
     247           0 :             case struct_type_t::STRUCT_TYPE_FLOAT32:
     248           0 :                 v.set_value(c.second->get_float32());
     249           0 :                 break;
     250             : 
     251           0 :             case struct_type_t::STRUCT_TYPE_FLOAT64:
     252           0 :                 v.set_value(c.second->get_float64());
     253           0 :                 break;
     254             : 
     255           0 :             case struct_type_t::STRUCT_TYPE_FLOAT128:
     256             :                 // TODO: we have to add support for long double in the
     257             :                 //       expression, for now use a double
     258             :                 //
     259           0 :                 v.set_value(static_cast<double>(c.second->get_float128()));
     260           0 :                 break;
     261             : 
     262           0 :             case struct_type_t::STRUCT_TYPE_P8STRING:
     263             :             case struct_type_t::STRUCT_TYPE_P16STRING:
     264             :             case struct_type_t::STRUCT_TYPE_P32STRING:
     265           0 :                 v.set_value(QString::fromUtf8(c.second->get_string().c_str()));
     266           0 :                 break;
     267             : 
     268           0 :             case struct_type_t::STRUCT_TYPE_STRUCTURE:
     269             :             case struct_type_t::STRUCT_TYPE_ARRAY8:
     270             :             case struct_type_t::STRUCT_TYPE_ARRAY16:
     271             :             case struct_type_t::STRUCT_TYPE_ARRAY32:
     272             :             case struct_type_t::STRUCT_TYPE_BUFFER8:
     273             :             case struct_type_t::STRUCT_TYPE_BUFFER16:
     274             :             case struct_type_t::STRUCT_TYPE_BUFFER32:
     275             :             case struct_type_t::STRUCT_TYPE_END:
     276             :             case struct_type_t::STRUCT_TYPE_RENAMED:
     277             :                 throw type_mismatch(
     278             :                           "Unexpected type ("
     279           0 :                         + std::to_string(static_cast<int>(schema->type()))
     280           0 :                         + ") to convert a cell from binary.");
     281             : 
     282             :             }
     283           0 :             variables[QString::fromUtf8(schema->name().c_str())] = v;
     284             :         }
     285             : 
     286           0 :         e.execute(return_value, variables, functions);
     287             : 
     288           0 :         libdbproxy::value const & value(return_value.get_value());
     289           0 :         switch(return_value.get_type())
     290             :         {
     291           0 :         case snap::snap_expr::variable_t::variable_type_t::EXPR_VARIABLE_TYPE_NULL:
     292             :             // done
     293           0 :             break;
     294             : 
     295           0 :         case snap::snap_expr::variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL:
     296             :             {
     297           0 :                 auto const v(value.safeBoolValue());
     298           0 :                 result.insert(result.end(), reinterpret_cast<uint8_t const *>(&v), reinterpret_cast<uint8_t const *>(&v + 1));
     299             :             }
     300           0 :             break;
     301             : 
     302           0 :         case snap::snap_expr::variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT8:
     303             :             {
     304           0 :                 auto const v(value.safeSignedCharValue());
     305           0 :                 result.insert(result.end(), reinterpret_cast<uint8_t const *>(&v), reinterpret_cast<uint8_t const *>(&v + 1));
     306             :             }
     307           0 :             break;
     308             : 
     309           0 :         case snap::snap_expr::variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT8:
     310             :             {
     311           0 :                 auto const v(value.safeUnsignedCharValue());
     312           0 :                 result.insert(result.end(), reinterpret_cast<uint8_t const *>(&v), reinterpret_cast<uint8_t const *>(&v + 1));
     313             :             }
     314           0 :             break;
     315             : 
     316           0 :         case snap::snap_expr::variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT16:
     317             :             {
     318           0 :                 auto const v(value.safeInt16Value());
     319           0 :                 result.insert(result.end(), reinterpret_cast<uint8_t const *>(&v), reinterpret_cast<uint8_t const *>(&v + 1));
     320             :             }
     321           0 :             break;
     322             : 
     323           0 :         case snap::snap_expr::variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT16:
     324             :             {
     325           0 :                 auto const v(value.safeUInt16Value());
     326           0 :                 result.insert(result.end(), reinterpret_cast<uint8_t const *>(&v), reinterpret_cast<uint8_t const *>(&v + 1));
     327             :             }
     328           0 :             break;
     329             : 
     330           0 :         case snap::snap_expr::variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT32:
     331             :             {
     332           0 :                 auto const v(value.safeInt32Value());
     333           0 :                 result.insert(result.end(), reinterpret_cast<uint8_t const *>(&v), reinterpret_cast<uint8_t const *>(&v + 1));
     334             :             }
     335           0 :             break;
     336             : 
     337           0 :         case snap::snap_expr::variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT32:
     338             :             {
     339           0 :                 auto const v(value.safeUInt32Value());
     340           0 :                 result.insert(result.end(), reinterpret_cast<uint8_t const *>(&v), reinterpret_cast<uint8_t const *>(&v + 1));
     341             :             }
     342           0 :             break;
     343             : 
     344           0 :         case snap::snap_expr::variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT64:
     345             :             {
     346           0 :                 auto const v(value.safeInt64Value());
     347           0 :                 result.insert(result.end(), reinterpret_cast<uint8_t const *>(&v), reinterpret_cast<uint8_t const *>(&v + 1));
     348             :             }
     349           0 :             break;
     350             : 
     351           0 :         case snap::snap_expr::variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT64:
     352             :             {
     353           0 :                 auto const v(value.safeUInt64Value());
     354           0 :                 result.insert(result.end(), reinterpret_cast<uint8_t const *>(&v), reinterpret_cast<uint8_t const *>(&v + 1));
     355             :             }
     356           0 :             break;
     357             : 
     358           0 :         case snap::snap_expr::variable_t::variable_type_t::EXPR_VARIABLE_TYPE_FLOAT:
     359             :             {
     360           0 :                 auto const v(value.safeFloatValue());
     361           0 :                 result.insert(result.end(), reinterpret_cast<uint8_t const *>(&v), reinterpret_cast<uint8_t const *>(&v + 1));
     362             :             }
     363           0 :             break;
     364             : 
     365           0 :         case snap::snap_expr::variable_t::variable_type_t::EXPR_VARIABLE_TYPE_DOUBLE:
     366             :             {
     367           0 :                 auto const v(value.safeDoubleValue());
     368           0 :                 result.insert(result.end(), reinterpret_cast<uint8_t const *>(&v), reinterpret_cast<uint8_t const *>(&v + 1));
     369             :             }
     370           0 :             break;
     371             : 
     372           0 :         case snap::snap_expr::variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING:
     373             :             {
     374           0 :                 auto const v(value.stringValue());
     375           0 :                 QByteArray data(v.toUtf8());
     376           0 :                 result.insert(result.end(), reinterpret_cast<uint8_t const *>(data.data()), reinterpret_cast<uint8_t const *>(data.data()) + data.size());
     377             :             }
     378           0 :             break;
     379             : 
     380           0 :         case snap::snap_expr::variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BINARY:
     381             :             {
     382           0 :                 auto const & v(value.binaryValue());
     383           0 :                 result.insert(result.end(), reinterpret_cast<uint8_t const *>(v.data()), reinterpret_cast<uint8_t const *>(v.data()) + v.size());
     384             :             }
     385           0 :             break;
     386             : 
     387             :         }
     388             : 
     389             :     }
     390           0 :     catch(snap::snap_expr::snap_expr_exception const & e)
     391             :     {
     392             :         // ignore all execution exceptions, but log a warning at least
     393             :         //
     394           0 :         SNAP_LOG_WARNING
     395           0 :             << "An error occurred while exceuting a script: "
     396           0 :             << e.what()
     397             :             << SNAP_LOG_SEND;
     398           0 :         return buffer_t();
     399             :     }
     400             : 
     401           0 :     return result;
     402             : }
     403             : 
     404             : 
     405             : 
     406           6 : } // namespace snapdatabase
     407             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13