session.cpp 11.6 KB
Newer Older
1
//
msobczak's avatar
msobczak committed
2
// Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton
3 4 5 6
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
msobczak's avatar
msobczak committed
7

8
#define SOCI_SOURCE
9 10 11 12 13
#include "soci/session.h"
#include "soci/connection-parameters.h"
#include "soci/connection-pool.h"
#include "soci/soci-backend.h"
#include "soci/query_transformation.h"
14 15 16 17

using namespace soci;
using namespace soci::details;

18 19 20
namespace // anonymous
{

msobczak's avatar
msobczak committed
21
void ensureConnected(session_backend * backEnd)
22 23 24 25 26 27 28
{
    if (backEnd == NULL)
    {
        throw soci_error("Session is not connected.");
    }
}

29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
// Standard logger class used by default.
class standard_logger_impl : public logger_impl
{
public:
    standard_logger_impl()
    {
        logStream_ = NULL;
    }

    virtual void start_query(std::string const & query)
    {
        if (logStream_ != NULL)
        {
            *logStream_ << query << '\n';
        }

        lastQuery_ = query;
    }

    virtual void set_stream(std::ostream * s)
    {
        logStream_ = s;
    }

    virtual std::ostream * get_stream() const
    {
        return logStream_;
    }

    virtual std::string get_last_query() const
    {
        return lastQuery_;
    }

private:
    virtual logger_impl* do_clone() const
    {
        return new standard_logger_impl;
    }

    std::ostream * logStream_;
    std::string lastQuery_;
};

73 74 75
} // namespace anonymous

session::session()
76 77
    : once(this), prepare(this), query_transformation_(NULL),
      logger_(new standard_logger_impl),
78
      uppercaseColumnNames_(false), backEnd_(NULL),
msobczak's avatar
msobczak committed
79
      isFromPool_(false), pool_(NULL)
80 81 82
{
}

83
session::session(connection_parameters const & parameters)
84 85
    : once(this), prepare(this), query_transformation_(NULL),
      logger_(new standard_logger_impl),
86
      lastConnectParameters_(parameters),
87 88 89
      uppercaseColumnNames_(false), backEnd_(NULL),
      isFromPool_(false), pool_(NULL)
{
90
    open(lastConnectParameters_);
91 92
}

93
session::session(backend_factory const & factory,
94
    std::string const & connectString)
95 96
    : once(this), prepare(this), query_transformation_(NULL),
    logger_(new standard_logger_impl),
97
      lastConnectParameters_(factory, connectString),
98
      uppercaseColumnNames_(false), backEnd_(NULL),
msobczak's avatar
msobczak committed
99
      isFromPool_(false), pool_(NULL)
100
{
101
    open(lastConnectParameters_);
102 103
}

104 105
session::session(std::string const & backendName,
    std::string const & connectString)
106 107
    : once(this), prepare(this), query_transformation_(NULL),
      logger_(new standard_logger_impl),
108
      lastConnectParameters_(backendName, connectString),
109
      uppercaseColumnNames_(false), backEnd_(NULL),
110 111
      isFromPool_(false), pool_(NULL)
{
112
    open(lastConnectParameters_);
113 114
}

115
session::session(std::string const & connectString)
116 117
    : once(this), prepare(this), query_transformation_(NULL),
      logger_(new standard_logger_impl),
118
      lastConnectParameters_(connectString),
119
      uppercaseColumnNames_(false), backEnd_(NULL),
msobczak's avatar
msobczak committed
120
      isFromPool_(false), pool_(NULL)
121
{
122
    open(lastConnectParameters_);
123 124
}

msobczak's avatar
msobczak committed
125
session::session(connection_pool & pool)
126 127 128
    : query_transformation_(NULL),
      logger_(new standard_logger_impl),
      isFromPool_(true), pool_(&pool)
msobczak's avatar
msobczak committed
129 130 131 132 133 134 135 136 137
{
    poolPosition_ = pool.lease();
    session & pooledSession = pool.at(poolPosition_);

    once.set_session(&pooledSession);
    prepare.set_session(&pooledSession);
    backEnd_ = pooledSession.get_backend();
}

138 139
session::~session()
{
msobczak's avatar
msobczak committed
140 141 142 143 144 145
    if (isFromPool_)
    {
        pool_->give_back(poolPosition_);
    }
    else
    {
146
        delete query_transformation_;
msobczak's avatar
msobczak committed
147 148
        delete backEnd_;
    }
149 150
}

151
void session::open(connection_parameters const & parameters)
152
{
msobczak's avatar
msobczak committed
153
    if (isFromPool_)
154
    {
155
        pool_->at(poolPosition_).open(parameters);
msobczak's avatar
msobczak committed
156 157 158 159 160 161 162 163
    }
    else
    {
        if (backEnd_ != NULL)
        {
            throw soci_error("Cannot open already connected session.");
        }

164 165 166 167 168 169 170 171
        backend_factory const * const factory = parameters.get_factory();
        if (factory == NULL)
        {
            throw soci_error("Cannot connect without a valid backend.");
        }

        backEnd_ = factory->make_session(parameters);
        lastConnectParameters_ = parameters;
172 173 174
    }
}

175
void session::open(backend_factory const & factory,
176 177
    std::string const & connectString)
{
178 179
    open(connection_parameters(factory, connectString));
}
180

181 182 183 184
void session::open(std::string const & backendName,
    std::string const & connectString)
{
    open(connection_parameters(backendName, connectString));
185 186
}

187 188
void session::open(std::string const & connectString)
{
189
    open(connection_parameters(connectString));
190 191
}

192 193
void session::close()
{
msobczak's avatar
msobczak committed
194 195 196
    if (isFromPool_)
    {
        pool_->at(poolPosition_).close();
xol's avatar
xol committed
197
        backEnd_ = NULL;
msobczak's avatar
msobczak committed
198 199 200 201 202 203
    }
    else
    {
        delete backEnd_;
        backEnd_ = NULL;
    }
204 205 206 207
}

void session::reconnect()
{
msobczak's avatar
msobczak committed
208
    if (isFromPool_)
209
    {
msobczak's avatar
msobczak committed
210
        pool_->at(poolPosition_).reconnect();
xol's avatar
xol committed
211
        backEnd_ = pool_->at(poolPosition_).get_backend();
212
    }
msobczak's avatar
msobczak committed
213
    else
214
    {
215 216
        backend_factory const * const lastFactory = lastConnectParameters_.get_factory();
        if (lastFactory == NULL)
msobczak's avatar
msobczak committed
217 218 219 220 221 222 223 224
        {
            throw soci_error("Cannot reconnect without previous connection.");
        }

        if (backEnd_ != NULL)
        {
            close();
        }
225

226
        backEnd_ = lastFactory->make_session(lastConnectParameters_);
msobczak's avatar
msobczak committed
227
    }
228 229
}

230 231
void session::begin()
{
232 233
    ensureConnected(backEnd_);

234 235 236 237 238
    backEnd_->begin();
}

void session::commit()
{
239 240
    ensureConnected(backEnd_);

241 242 243 244 245
    backEnd_->commit();
}

void session::rollback()
{
246 247
    ensureConnected(backEnd_);

248 249 250
    backEnd_->rollback();
}

251 252
std::ostringstream & session::get_query_stream()
{
msobczak's avatar
msobczak committed
253 254 255 256 257 258 259 260
    if (isFromPool_)
    {
        return pool_->at(poolPosition_).get_query_stream();
    }
    else
    {
        return query_stream_;
    }
261 262
}

263 264
std::string session::get_query() const
{
265 266 267 268 269 270 271
    if (isFromPool_)
    {
        return pool_->at(poolPosition_).get_query();
    }
    else
    {
        // preserve logical constness of get_query,
272
        // stream used as read-only here,
273 274 275 276 277 278 279 280 281 282
        session* pthis = const_cast<session*>(this);

        // sole place where any user-defined query transformation is applied
        if (query_transformation_)
        {
            return (*query_transformation_)(pthis->get_query_stream().str());
        }
        return pthis->get_query_stream().str();
    }
}
283

284

285
void session::set_query_transformation_(cxx_details::auto_ptr<details::query_transformation_function>& qtf)
286 287
{
    if (isFromPool_)
288
    {
289 290 291 292 293 294
        pool_->at(poolPosition_).set_query_transformation_(qtf);
    }
    else
    {
        delete query_transformation_;
        query_transformation_= qtf.release();
295 296 297
    }
}

298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
void session::set_logger(logger const & logger)
{
    if (isFromPool_)
    {
        pool_->at(poolPosition_).set_logger(logger);
    }
    else
    {
        logger_ = logger;
    }
}

logger const & session::get_logger() const
{
    if (isFromPool_)
    {
        return pool_->at(poolPosition_).get_logger();
    }
    else
    {
        return logger_;
    }
}

msobczak's avatar
msobczak committed
322
void session::set_log_stream(std::ostream * s)
323
{
msobczak's avatar
msobczak committed
324 325 326 327 328 329
    if (isFromPool_)
    {
        pool_->at(poolPosition_).set_log_stream(s);
    }
    else
    {
330
        logger_.set_stream(s);
msobczak's avatar
msobczak committed
331
    }
332 333 334 335
}

std::ostream * session::get_log_stream() const
{
msobczak's avatar
msobczak committed
336 337 338 339 340 341
    if (isFromPool_)
    {
        return pool_->at(poolPosition_).get_log_stream();
    }
    else
    {
342
        return logger_.get_stream();
msobczak's avatar
msobczak committed
343
    }
344 345
}

msobczak's avatar
msobczak committed
346
void session::log_query(std::string const & query)
347
{
msobczak's avatar
msobczak committed
348
    if (isFromPool_)
349
    {
msobczak's avatar
msobczak committed
350
        pool_->at(poolPosition_).log_query(query);
351
    }
msobczak's avatar
msobczak committed
352 353
    else
    {
354
        logger_.start_query(query);
msobczak's avatar
msobczak committed
355
    }
356 357 358 359
}

std::string session::get_last_query() const
{
msobczak's avatar
msobczak committed
360 361 362 363 364 365
    if (isFromPool_)
    {
        return pool_->at(poolPosition_).get_last_query();
    }
    else
    {
366
        return logger_.get_last_query();
msobczak's avatar
msobczak committed
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415
    }
}

void session::set_got_data(bool gotData)
{
    if (isFromPool_)
    {
        pool_->at(poolPosition_).set_got_data(gotData);
    }
    else
    {
        gotData_ = gotData;
    }
}

bool session::got_data() const
{
    if (isFromPool_)
    {
        return pool_->at(poolPosition_).got_data();
    }
    else
    {
        return gotData_;
    }
}

void session::uppercase_column_names(bool forceToUpper)
{
    if (isFromPool_)
    {
        pool_->at(poolPosition_).uppercase_column_names(forceToUpper);
    }
    else
    {
        uppercaseColumnNames_ = forceToUpper;
    }
}

bool session::get_uppercase_column_names() const
{
    if (isFromPool_)
    {
        return pool_->at(poolPosition_).get_uppercase_column_names();
    }
    else
    {
        return uppercaseColumnNames_;
    }
416 417
}

418 419 420 421 422 423 424 425 426 427 428 429 430 431
bool session::get_next_sequence_value(std::string const & sequence, long & value)
{
    ensureConnected(backEnd_);

    return backEnd_->get_next_sequence_value(*this, sequence, value);
}

bool session::get_last_insert_id(std::string const & sequence, long & value)
{
    ensureConnected(backEnd_);

    return backEnd_->get_last_insert_id(*this, sequence, value);
}

432 433
details::once_temp_type session::get_table_names()
{
434 435
    ensureConnected(backEnd_);

436 437 438 439 440
    return once << backEnd_->get_table_names_query();
}

details::prepare_temp_type session::prepare_table_names()
{
441 442
    ensureConnected(backEnd_);

443 444 445 446 447
    return prepare << backEnd_->get_table_names_query();
}

details::prepare_temp_type session::prepare_column_descriptions(std::string & table_name)
{
448 449
    ensureConnected(backEnd_);

450 451 452
    return prepare << backEnd_->get_column_descriptions_query(), use(table_name, "t");
}
    
453 454 455 456 457 458 459 460 461 462 463 464
ddl_type session::create_table(const std::string & tableName)
{
    ddl_type ddl(*this);

    ddl.create_table(tableName);
    ddl.set_tail(")");

    return ddl;
}

void session::drop_table(const std::string & tableName)
{
465 466
    ensureConnected(backEnd_);

467 468 469 470 471
    once << backEnd_->drop_table(tableName);
}

void session::truncate_table(const std::string & tableName)
{
472 473
    ensureConnected(backEnd_);

474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
    once << backEnd_->truncate_table(tableName);
}

ddl_type session::add_column(const std::string & tableName,
    const std::string & columnName, data_type dt,
    int precision, int scale)
{
    ddl_type ddl(*this);

    ddl.add_column(tableName, columnName, dt, precision, scale);

    return ddl;
}

ddl_type session::alter_column(const std::string & tableName,
    const std::string & columnName, data_type dt,
    int precision, int scale)
{
    ddl_type ddl(*this);

    ddl.alter_column(tableName, columnName, dt, precision, scale);

    return ddl;
}

ddl_type session::drop_column(const std::string & tableName,
    const std::string & columnName)
{
    ddl_type ddl(*this);

    ddl.drop_column(tableName, columnName);

    return ddl;
}

509 510
std::string session::empty_blob()
{
511 512
    ensureConnected(backEnd_);

513 514 515 516 517
    return backEnd_->empty_blob();
}

std::string session::nvl()
{
518 519
    ensureConnected(backEnd_);

520 521 522
    return backEnd_->nvl();
}

523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538
std::string session::get_dummy_from_table() const
{
    ensureConnected(backEnd_);

    return backEnd_->get_dummy_from_table();
}

std::string session::get_dummy_from_clause() const
{
    std::string clause = get_dummy_from_table();
    if (!clause.empty())
        clause.insert(0, " from ");

    return clause;
}

539 540 541 542 543 544 545
void session::set_failover_callback(failover_callback & callback)
{
    ensureConnected(backEnd_);

    backEnd_->set_failover_callback(callback, *this);
}

msobczak's avatar
msobczak committed
546 547
std::string session::get_backend_name() const
{
548 549
    ensureConnected(backEnd_);

msobczak's avatar
msobczak committed
550 551 552
    return backEnd_->get_backend_name();
}

553 554
statement_backend * session::make_statement_backend()
{
555 556
    ensureConnected(backEnd_);

557 558 559 560 561
    return backEnd_->make_statement_backend();
}

rowid_backend * session::make_rowid_backend()
{
562 563
    ensureConnected(backEnd_);

564 565 566 567 568
    return backEnd_->make_rowid_backend();
}

blob_backend * session::make_blob_backend()
{
569 570
    ensureConnected(backEnd_);

571 572
    return backEnd_->make_blob_backend();
}