• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

polserver / polserver / 25918451630

15 May 2026 12:43PM UTC coverage: 60.929% (+2.1%) from 58.859%
25918451630

push

github

turleypol
added dynamic property which returns a pointer of the object instead of
a copy like the current imp.
needed to be able to eg store a vector

43 of 61 new or added lines in 2 files covered. (70.49%)

14455 existing lines in 345 files now uncovered.

44695 of 73356 relevant lines covered (60.93%)

449621.59 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

55.52
/pol-core/pol/sqlscrobj.cpp
1
/** @file
2
 *
3
 * @par History
4
 */
5

6

7
#include "sqlscrobj.h"
8

9
#include <exception>
10
#include <regex>
11
#include <string.h>
12

13
#include "../bscript/berror.h"
14
#include "../bscript/bobject.h"
15
#include "../bscript/contiter.h"
16
#include "../bscript/impstr.h"
17
#include "../bscript/objmembers.h"
18
#include "../bscript/objmethods.h"
19
#include "../clib/esignal.h"
20
#include "../clib/logfacility.h"
21
#include "../clib/threadhelp.h"
22
#include "globals/network.h"
23

24

25
namespace Pol::Core
26
{
27
using namespace Bscript;
28

29
BSQLRow::BSQLRow( BSQLResultSet* resultset ) : PolObjectImp( OTSQLRow )
10✔
30
{
31
  _result = resultset->_result;
10✔
32
  _row = mysql_fetch_row( _result->ptr() );
10✔
33
  _fields = mysql_fetch_fields( _result->ptr() );
10✔
34
}
10✔
UNCOV
35
BSQLRow::BSQLRow( RES_WRAPPER result ) : PolObjectImp( OTSQLRow )
×
36
{
UNCOV
37
  _result = result;
×
UNCOV
38
  _row = mysql_fetch_row( _result->ptr() );
×
UNCOV
39
  _fields = mysql_fetch_fields( _result->ptr() );
×
40
}
×
UNCOV
41
BSQLRow::BSQLRow( RES_WRAPPER result, MYSQL_ROW row, MYSQL_FIELD* fields )
×
42
    : PolObjectImp( OTSQLRow ), _row( row ), _result( result ), _fields( fields )
×
43
{
44
}
×
45

46
class SQLRowIterator final : public Bscript::ContIterator
47
{
48
public:
49
  SQLRowIterator( BSQLRow* node, Bscript::BObject* pIter );
50
  Bscript::BObject* step() override;
51

52
private:
53
  Bscript::BObject m_RowObj;
54
  BSQLRow* rowimp;
55
  Bscript::BObjectRef m_IterVal;
56
  unsigned int index;
57
};
58

59
SQLRowIterator::SQLRowIterator( BSQLRow* row, Bscript::BObject* pIter )
4✔
60
    : ContIterator(), m_RowObj( row ), rowimp( row ), m_IterVal( pIter ), index( 0 )
4✔
61
{
62
}
4✔
63

64
Bscript::BObject* SQLRowIterator::step()
10✔
65
{
66
  unsigned int num_fields = mysql_num_fields( rowimp->_result->ptr() );
10✔
67
  const auto& fields = rowimp->_fields;
10✔
68
  const auto& row = rowimp->_row;
10✔
69

70
  if ( index >= num_fields )
10✔
71
    return nullptr;
2✔
72

73
  m_IterVal->setimp( new String( fields[index].name ) );
8✔
74

75
  if ( IS_NUM( fields[index].type ) && fields[index].type != MYSQL_TYPE_TIMESTAMP )
8✔
76
  {
77
    if ( fields[index].type == MYSQL_TYPE_DECIMAL || fields[index].type == MYSQL_TYPE_NEWDECIMAL ||
4✔
78
         fields[index].type == MYSQL_TYPE_FLOAT || fields[index].type == MYSQL_TYPE_DOUBLE )
4✔
UNCOV
79
      return new BObject( new Double( strtod( row[index++], nullptr ) ) );
×
80
    return new BObject( new BLong( strtoul( row[index++], nullptr, 0 ) ) );
4✔
81
  }
82

83
  return new BObject( new String( row[index++], String::Tainted::YES ) );
4✔
84
}
85

86
ContIterator* BSQLRow::createIterator( Bscript::BObject* pIterVal )
4✔
87
{
88
  if ( !_result )
8✔
89
  {
UNCOV
90
    return BObjectImp::createIterator( pIterVal );
×
91
  }
92
  return new SQLRowIterator( this, pIterVal );
4✔
93
}
94

95
BObjectRef BSQLRow::OperSubscript( const BObject& obj )
6✔
96
{
97
  const Bscript::BObjectImp& right = obj.impref();
6✔
98
  if ( _result == nullptr )
6✔
UNCOV
99
    return BObjectRef( new BError( "No result" ) );
×
100
  unsigned int num_fields = mysql_num_fields( _result->ptr() );
6✔
101
  if ( right.isa( OTLong ) )  // vector
6✔
102
  {
103
    BLong& lng = (BLong&)right;
6✔
104

105
    unsigned index = (unsigned)lng.value();
6✔
106
    if ( index > num_fields || index <= 0 )
6✔
107
    {
UNCOV
108
      return BObjectRef( new BError( "Index out of bounds" ) );
×
109
    }
110
    if ( _row[index - 1] == nullptr )
6✔
111
    {
UNCOV
112
      return BObjectRef( UninitObject::create() );
×
113
    }
114
    if ( IS_NUM( _fields[index - 1].type ) && _fields[index - 1].type != MYSQL_TYPE_TIMESTAMP )
6✔
115
    {
UNCOV
116
      if ( _fields[index - 1].type == MYSQL_TYPE_DECIMAL ||
×
117
           _fields[index - 1].type == MYSQL_TYPE_NEWDECIMAL ||
×
UNCOV
118
           _fields[index - 1].type == MYSQL_TYPE_FLOAT ||
×
UNCOV
119
           _fields[index - 1].type == MYSQL_TYPE_DOUBLE )
×
UNCOV
120
        return BObjectRef( new Double( strtod( _row[index - 1], nullptr ) ) );
×
121
      return BObjectRef( new BLong( strtoul( _row[index - 1], nullptr, 0 ) ) );
×
122
    }
123
    return BObjectRef( new String( _row[index - 1], String::Tainted::YES ) );
6✔
124
  }
125
  if ( right.isa( OTString ) )
×
126
  {
UNCOV
127
    String& string = (String&)right;
×
UNCOV
128
    for ( unsigned int i = 0; i < num_fields; i++ )
×
129
    {
130
      if ( !strncmp( _fields[i].name, string.data(), _fields[i].name_length ) )
×
131
      {
132
        if ( _row[i] == nullptr )
×
133
        {
UNCOV
134
          return BObjectRef( UninitObject::create() );
×
135
        }
UNCOV
136
        if ( IS_NUM( _fields[i].type ) && _fields[i].type != MYSQL_TYPE_TIMESTAMP )
×
137
        {
UNCOV
138
          if ( _fields[i].type == MYSQL_TYPE_DECIMAL || _fields[i].type == MYSQL_TYPE_NEWDECIMAL ||
×
139
               _fields[i].type == MYSQL_TYPE_FLOAT || _fields[i].type == MYSQL_TYPE_DOUBLE )
×
UNCOV
140
            return BObjectRef( new Double( strtod( _row[i], nullptr ) ) );
×
141
          return BObjectRef( new BLong( strtoul( _row[i], nullptr, 0 ) ) );
×
142
        }
143
        return BObjectRef( new String( _row[i], String::Tainted::YES ) );
×
144
      }
145
    }
146
    return BObjectRef( new BError( "Column does not exist" ) );
×
147
  }
148

UNCOV
149
  return BObjectRef( new BError( "SQLRow keys must be integer" ) );
×
150
}
151
BSQLRow::~BSQLRow() = default;
20✔
UNCOV
152
Bscript::BObjectImp* BSQLRow::copy() const
×
153
{
UNCOV
154
  return new BSQLRow( _result, _row, _fields );
×
155
}
156

157
BSQLResultSet::BSQLResultSet( RES_WRAPPER result )
4✔
158
    : Bscript::BObjectImp( OTSQLResultSet ),
159
      _result( result ),
4✔
160
      _fields( nullptr ),
4✔
161
      _affected_rows( 0 )
4✔
162
{
163
  if ( result->ptr() != nullptr )
4✔
164
    _fields = mysql_fetch_fields( result->ptr() );
4✔
165
}
4✔
UNCOV
166
BSQLResultSet::BSQLResultSet( RES_WRAPPER result, MYSQL_FIELD* fields )
×
167
    : Bscript::BObjectImp( OTSQLResultSet ),
UNCOV
168
      _result( result ),
×
UNCOV
169
      _fields( fields ),
×
UNCOV
170
      _affected_rows( 0 )
×
171
{
UNCOV
172
}
×
173
BSQLResultSet::BSQLResultSet( int affected_rows )
4✔
174
    : Bscript::BObjectImp( OTSQLResultSet ),
175
      _result( nullptr ),
4✔
176
      _fields( nullptr ),
4✔
177
      _affected_rows( affected_rows )
4✔
178
{
179
}
4✔
180

181
class SQLResultSetIterator final : public Bscript::ContIterator
182
{
183
public:
184
  SQLResultSetIterator( BSQLResultSet* node, Bscript::BObject* pIter );
185
  Bscript::BObject* step() override;
186

187
private:
188
  Bscript::BObject m_ResultsObj;
189
  BSQLResultSet* results;
190
  Bscript::BObjectRef m_IterVal;
191
  BLong* m_pIterVal;
192
};
193

194
SQLResultSetIterator::SQLResultSetIterator( BSQLResultSet* results, Bscript::BObject* pIterVal )
2✔
195
    : ContIterator(),
196
      m_ResultsObj( results ),
2✔
197
      results( results ),
2✔
198
      m_IterVal( pIterVal ),
2✔
199
      m_pIterVal( new BLong( 0 ) )
4✔
200
{
201
  m_IterVal.get()->setimp( m_pIterVal );
2✔
202
}
2✔
203

204
Bscript::BObject* SQLResultSetIterator::step()
6✔
205
{
206
  if ( static_cast<uint64_t>( m_pIterVal->value() ) >= mysql_num_rows( results->_result->ptr() ) )
6✔
207
    return nullptr;
2✔
208

209
  m_pIterVal->increment();
4✔
210
  return new BObject( new BSQLRow( results ) );
4✔
211
}
212

213
ContIterator* BSQLResultSet::createIterator( Bscript::BObject* pIterVal )
2✔
214
{
215
  if ( !_result )
4✔
216
  {
UNCOV
217
    return BObjectImp::createIterator( pIterVal );
×
218
  }
219
  return new SQLResultSetIterator( this, pIterVal );
2✔
220
}
221

UNCOV
222
const char* BSQLResultSet::field_name( unsigned int index ) const
×
223
{
224
  if ( !_result || _result->ptr() == nullptr )
×
UNCOV
225
    return nullptr;
×
UNCOV
226
  if ( index <= 0 || index > mysql_num_fields( _result->ptr() ) )
×
227
  {
UNCOV
228
    return nullptr;
×
229
  }
UNCOV
230
  return _fields[index - 1].name;
×
231
}
232
int BSQLResultSet::num_rows() const
6✔
233
{
234
  if ( !_result )
12✔
235
    return 0;
×
236
  return static_cast<int>( mysql_num_rows( _result->ptr() ) );
6✔
237
};
238

239
bool BSQLResultSet::has_result() const
6✔
240
{
241
  return _result && _result->ptr();
12✔
242
}
243

UNCOV
244
Bscript::BObjectImp* BSQLResultSet::copy() const
×
245
{
UNCOV
246
  if ( _affected_rows )
×
UNCOV
247
    return new BSQLResultSet( _affected_rows );
×
UNCOV
248
  return new BSQLResultSet( _result, _fields );
×
249
};
250

251
int BSQLResultSet::num_fields() const
×
252
{
253
  if ( _result && _result->ptr() != nullptr )
×
254
    return mysql_num_fields( _result->ptr() );
×
UNCOV
255
  return 0;
×
256
}
UNCOV
257
int BSQLResultSet::affected_rows() const
×
258
{
259
  return _affected_rows;
×
260
}
261
BSQLResultSet::~BSQLResultSet() = default;
16✔
262
bool BSQLResultSet::isTrue() const
4✔
263
{
264
  return true;
4✔
265
}
UNCOV
266
std::string BSQLResultSet::getStringRep() const
×
267
{
UNCOV
268
  return "SQLResultSet";
×
269
}
270

UNCOV
271
bool BSQLConnection::close()
×
272
{
UNCOV
273
  _conn->set( nullptr );
×
274
  return true;
×
275
}
276
Bscript::BObjectImp* BSQLConnection::getResultSet() const
8✔
277
{
278
  if ( _errno )
8✔
279
    return new BError( _error );
×
280
  RES_WRAPPER result = std::make_shared<ResultWrapper>( mysql_store_result( _conn->ptr() ) );
8✔
281
  if ( result && result->ptr() != nullptr )  // there are rows
8✔
282
  {
283
    return new BSQLResultSet( result );
4✔
284
    // retrieve rows, then call mysql_free_result(result)
285
  }
286
  // mysql_store_result() returned nothing; should it have?
287
  /*  if (mysql_errno(_conn))
288
    {
289
      _error = mysql_error(_conn);
290
      _errno = mysql_errno(_conn);
291
      return new BError(_error);
292
    }
293
    else */
294
  if ( mysql_field_count( _conn->ptr() ) == 0 )
4✔
295
  {
296
    return new BSQLResultSet( static_cast<int>( mysql_affected_rows( _conn->ptr() ) ) );
4✔
297
  }
298

UNCOV
299
  return new BError( "Unknown error getting ResultSet" );
×
300
}
8✔
301
BSQLConnection::BSQLConnection()
1✔
302
    : PolObjectImp( OTSQLConnection ), _conn( new ConnectionWrapper ), _errno( 0 )
1✔
303
{
304
  _conn->set( mysql_init( nullptr ) );
1✔
305
  if ( !_conn->ptr() )
1✔
306
  {
UNCOV
307
    _error = "Insufficient memory";
×
308
    _errno = 1;
×
309
  }
310
}
1✔
311

UNCOV
312
BSQLConnection::BSQLConnection( std::shared_ptr<ConnectionWrapper> conn )
×
UNCOV
313
    : PolObjectImp( OTSQLConnection ), _conn( conn ), _errno( 0 )
×
314
{
UNCOV
315
}
×
316

317
BSQLConnection::~BSQLConnection() = default;
2✔
UNCOV
318
std::string BSQLConnection::getStringRep() const
×
319
{
UNCOV
320
  return "SQLConnection";
×
321
}
322
bool BSQLConnection::isTrue() const
1✔
323
{
324
  if ( !_conn->ptr() )
1✔
UNCOV
325
    return false;  // closed by hand
×
326
  if ( !mysql_ping( _conn->ptr() ) )
1✔
327
    return true;
1✔
UNCOV
328
  return false;
×
329
}
330
bool BSQLConnection::connect( const char* host, const char* user, const char* passwd, int port )
1✔
331
{
332
  if ( !_conn->ptr() )
1✔
333
  {
334
    _errno = -1;
×
UNCOV
335
    _error = "No active MYSQL object instance.";
×
UNCOV
336
    return false;
×
337
  }
338
  // port == 0 means default sql port
339
  if ( !mysql_real_connect( _conn->ptr(), host, user, passwd, nullptr, port, nullptr, 0 ) )
1✔
340
  {
UNCOV
341
    _errno = mysql_errno( _conn->ptr() );
×
UNCOV
342
    _error = mysql_error( _conn->ptr() );
×
343
    return false;
×
344
  }
345
  return true;
1✔
346
}
347
bool BSQLConnection::select_db( const char* db )
1✔
348
{
349
  if ( !_conn->ptr() )
1✔
350
  {
351
    _errno = -1;
×
352
    _error = "No active MYSQL object instance.";
×
UNCOV
353
    return false;
×
354
  }
355
  if ( mysql_select_db( _conn->ptr(), db ) )
1✔
356
  {
UNCOV
357
    _errno = mysql_errno( _conn->ptr() );
×
UNCOV
358
    _error = mysql_error( _conn->ptr() );
×
UNCOV
359
    return false;
×
360
  }
361
  return true;
1✔
362
}
363

364
bool BSQLConnection::query( const std::string query )
8✔
365
{
366
  if ( !_conn->ptr() )
8✔
367
  {
368
    _errno = -1;
×
UNCOV
369
    _error = "No active MYSQL object instance.";
×
UNCOV
370
    return false;
×
371
  }
372

373
  if ( mysql_query( _conn->ptr(), query.c_str() ) )
8✔
374
  {
UNCOV
375
    _errno = mysql_errno( _conn->ptr() );
×
UNCOV
376
    _error = mysql_error( _conn->ptr() );
×
377
    return false;
×
378
  }
379

380
  return true;
8✔
381
}
382

383
/*
384
 * Allows binding parameters to the query
385
 * Every occurrence of "?" is replaced with a single parameter
386
 */
387
bool BSQLConnection::query( const std::string query, QueryParams params )
8✔
388
{
389
  if ( params == nullptr || params->empty() )
8✔
390
    return this->query( query );
7✔
391

392
  if ( !_conn->ptr() )
1✔
393
  {
UNCOV
394
    _errno = -1;
×
UNCOV
395
    _error = "No active MYSQL object instance.";
×
UNCOV
396
    return false;
×
397
  }
398

399
  std::string replaced = query;
1✔
400
  std::regex re( "^((?:[^']|'[^']*')*?)(\\?)" );
1✔
401
  for ( auto& it : *params )
3✔
402
  {
403
    if ( !std::regex_search( replaced, re ) )
2✔
404
    {
405
      _errno = -2;
×
UNCOV
406
      _error = "Could not replace parameters.";
×
UNCOV
407
      return false;
×
408
    }
409

410
    if ( it.size() > ( std::numeric_limits<size_t>::max() - 5 ) / 2 )
2✔
411
    {
UNCOV
412
      _errno = -3;
×
UNCOV
413
      _error = "Parameter is too long.";
×
414
    }
415

416
    // Escape the string and add quoting. A bit tricky, but effective.
417
    size_t escaped_max_size =
418
        it.size() * 2 + 5;  // max is +1, using +5 to leave space for quoting and "$1"
2✔
419
    std::unique_ptr<char[]> escptr(
420
        new char[escaped_max_size] );  // will contain the escaped string
2✔
421
    // use +3 to leave space for quoting
422
    unsigned long esclen = mysql_real_escape_string( _conn->ptr(), escptr.get() + 3, it.c_str(),
2✔
423
                                                     static_cast<unsigned long>( it.size() ) );
2✔
424
    // Now add quoting, equivalent to escptr = "$1'" + escptr + "'"
425
    esclen += 4;
2✔
426
    escptr[0] = '$';
2✔
427
    escptr[1] = '1';
2✔
428
    escptr[2] = '\'';
2✔
429
    escptr[esclen - 1] = '\'';
2✔
430
    escptr[esclen] = '\0';
2✔
431

432
    replaced =
433
        std::regex_replace( replaced, re, escptr.get(), std::regex_constants::format_first_only );
2✔
434
  }
2✔
435

436
  return this->query( replaced );
1✔
437
}
1✔
438

439
bool BSQLConnection::escape_string( const std::string& text, std::string* escaped ) const
1✔
440
{
441
  if ( !_conn->ptr() )
1✔
UNCOV
442
    return false;
×
443
  *escaped = std::string( text.size() * 2 + 1, '\0' );
1✔
444
  if ( mysql_real_escape_string( _conn->ptr(), escaped->data(), text.data(),
1✔
445
                                 (unsigned long)text.size() ) == (unsigned long)-1 )
2✔
UNCOV
446
    return false;
×
447
  escaped->resize( escaped->find_first_of( '\0' ) );
1✔
448
  return true;
1✔
449
}
450

451
std::string BSQLConnection::getLastError() const
×
452
{
UNCOV
453
  return _error;
×
454
}
455
int BSQLConnection::getLastErrNo() const
1✔
456
{
457
  return _errno;
1✔
458
}
UNCOV
459
std::shared_ptr<BSQLConnection::ConnectionWrapper> BSQLConnection::getConnection() const
×
460
{
UNCOV
461
  return _conn;
×
462
}
463

464

UNCOV
465
BObjectRef BSQLConnection::get_member_id( const int /*id*/ )  // id test
×
466
{
UNCOV
467
  return BObjectRef( UninitObject::create() );
×
468
  // switch(id)
469
  //{
470

471
  //  default: return BObjectRef(UninitObject::create());
472
  //}
473
}
474
BObjectRef BSQLConnection::get_member( const char* membername )
×
475
{
476
  ObjMember* objmember = getKnownObjMember( membername );
×
UNCOV
477
  if ( objmember != nullptr )
×
UNCOV
478
    return this->get_member_id( objmember->id );
×
UNCOV
479
  return BObjectRef( UninitObject::create() );
×
480
}
481

UNCOV
482
Bscript::BObjectImp* BSQLConnection::call_polmethod( const char* methodname, UOExecutor& ex )
×
483
{
UNCOV
484
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
485
  if ( objmethod != nullptr )
×
486
    return this->call_polmethod_id( objmethod->id, ex );
×
487
  return nullptr;
×
488
}
489

UNCOV
490
Bscript::BObjectImp* BSQLConnection::call_polmethod_id( const int /*id*/, UOExecutor& /*ex*/,
×
491
                                                        bool /*forcebuiltin*/ )
492
{
UNCOV
493
  return new BLong( 0 );
×
494
}
495

496
Bscript::BObjectImp* BSQLConnection::copy() const
×
497
{
498
  return new BSQLConnection( _conn );
×
499
}
500

501
BSQLConnection::ConnectionWrapper::ConnectionWrapper() : _conn( nullptr ) {}
1✔
502
BSQLConnection::ConnectionWrapper::~ConnectionWrapper()
1✔
503
{
504
  if ( _conn )
1✔
505
    mysql_close( _conn );
1✔
506
  _conn = nullptr;
1✔
507
}
1✔
508
void BSQLConnection::ConnectionWrapper::set( MYSQL* conn )
1✔
509
{
510
  if ( _conn )
1✔
UNCOV
511
    mysql_close( _conn );
×
512
  _conn = conn;
1✔
513
}
1✔
514
MYSQL* BSQLConnection::ConnectionWrapper::ptr()
44✔
515
{
516
  return _conn;
44✔
517
};
518

519
ResultWrapper::ResultWrapper( MYSQL_RES* res ) : _result( res ) {}
8✔
UNCOV
520
ResultWrapper::ResultWrapper() : _result( nullptr ) {}
×
521
ResultWrapper::~ResultWrapper()
8✔
522
{
523
  if ( _result )
8✔
524
    mysql_free_result( _result );
4✔
525
  _result = nullptr;
8✔
526
}
8✔
UNCOV
527
void ResultWrapper::set( MYSQL_RES* result )
×
528
{
UNCOV
529
  if ( _result )
×
UNCOV
530
    mysql_free_result( _result );
×
531
  _result = result;
×
UNCOV
532
}
×
533
MYSQL_RES* ResultWrapper::ptr()
70✔
534
{
535
  return _result;
70✔
536
}
537

538

539
void sql_service_thread_stub()
2✔
540
{
541
  try
542
  {
543
    networkManager.sql_service->start();
2✔
544
  }
UNCOV
545
  catch ( const char* msg )
×
546
  {
UNCOV
547
    POLLOGLN( "SQL Thread exits due to exception: {}", msg );
×
UNCOV
548
    throw;
×
UNCOV
549
  }
×
UNCOV
550
  catch ( std::string& str )
×
551
  {
UNCOV
552
    POLLOGLN( "SQL Thread exits due to exception: {}", str );
×
UNCOV
553
    throw;
×
UNCOV
554
  }
×
UNCOV
555
  catch ( std::exception& ex )
×
556
  {
UNCOV
557
    POLLOGLN( "SQL Thread exits due to exception: {}", ex.what() );
×
558
    throw;
×
559
  }
×
560
}
2✔
561

562
SQLService::SQLService() = default;
3✔
563
SQLService::~SQLService() = default;
3✔
564
void SQLService::stop()
2✔
565
{
566
  _msgs.cancel();
2✔
567
}
2✔
568
void SQLService::push( msg&& msg_ )
10✔
569
{
570
  _msgs.push_move( std::move( msg_ ) );
10✔
571
}
10✔
572
void SQLService::start()  // executed inside a extra thread
2✔
573
{
574
  while ( !Clib::exit_signalled )
12✔
575
  {
576
    try
577
    {
578
      msg task;
12✔
579
      _msgs.pop_wait( &task );
12✔
580
      task();
10✔
581
    }
12✔
582
    catch ( msg_queue::Canceled& )
2✔
583
    {
584
      break;
2✔
585
    }
2✔
586
    // ignore remaining tasks
587
  }
588
}
2✔
589

590

591
void start_sql_service()
2✔
592
{
593
  threadhelp::start_thread( sql_service_thread_stub, "SQLService" );
2✔
594
}
2✔
595
}  // namespace Pol::Core
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc