OmniSciDB  4201147b46
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Parser::InsertValuesStmt Class Reference

#include <ParserNode.h>

+ Inheritance diagram for Parser::InsertValuesStmt:
+ Collaboration diagram for Parser::InsertValuesStmt:

Public Member Functions

 InsertValuesStmt (const rapidjson::Value &payload)
 
 InsertValuesStmt (std::string *t, std::list< std::string * > *c, std::list< Expr * > *v)
 
const std::vector
< std::unique_ptr< ValuesList > > & 
get_value_lists () const
 
void analyze (const Catalog_Namespace::Catalog &catalog, Analyzer::Query &query) const override
 
void execute (const Catalog_Namespace::SessionInfo &session, bool read_only_mode)
 
- Public Member Functions inherited from Parser::InsertStmt
 InsertStmt (std::string *t, std::list< std::string * > *c)
 
const std::string * get_table () const
 
const std::list
< std::unique_ptr< std::string > > & 
get_column_list () const
 
- Public Member Functions inherited from Parser::Node
virtual ~Node ()
 

Public Attributes

Fragmenter_Namespace::InsertDataLoader::InsertConnectorleafs_connector_ = nullptr
 

Private Attributes

std::vector< std::unique_ptr
< ValuesList > > 
values_lists_
 

Additional Inherited Members

- Protected Attributes inherited from Parser::InsertStmt
std::unique_ptr< std::string > table_
 
std::list< std::unique_ptr
< std::string > > 
column_list_
 

Detailed Description

Definition at line 2123 of file ParserNode.h.

Constructor & Destructor Documentation

Parser::InsertValuesStmt::InsertValuesStmt ( const rapidjson::Value &  payload)

Definition at line 2401 of file ParserNode.cpp.

References CHECK, Parser::InsertStmt::column_list_, json_str(), Parser::anonymous_namespace{ParserNode.cpp}::parse_insert_array_literal(), Parser::anonymous_namespace{ParserNode.cpp}::parse_insert_literal(), Parser::InsertStmt::table_, and values_lists_.

2402  : InsertStmt(nullptr, nullptr) {
2403  CHECK(payload.HasMember("name"));
2404  table_ = std::make_unique<std::string>(json_str(payload["name"]));
2405 
2406  if (payload.HasMember("columns")) {
2407  CHECK(payload["columns"].IsArray());
2408  for (auto& column : payload["columns"].GetArray()) {
2409  std::string s = json_str(column);
2410  column_list_.emplace_back(std::make_unique<std::string>(s));
2411  }
2412  }
2413 
2414  CHECK(payload.HasMember("values") && payload["values"].IsArray());
2415  auto tuples = payload["values"].GetArray();
2416  if (tuples.Empty()) {
2417  throw std::runtime_error("Values statement cannot be empty");
2418  }
2419  values_lists_.reserve(tuples.Size());
2420  for (const auto& json_tuple : tuples) {
2421  auto values_list = std::make_unique<ValuesList>();
2422  CHECK(json_tuple.IsArray());
2423  auto tuple = json_tuple.GetArray();
2424  for (const auto& value : tuple) {
2425  CHECK(value.IsObject());
2426  if (value.HasMember("array")) {
2427  values_list->push_back(parse_insert_array_literal(value["array"]));
2428  } else {
2429  values_list->push_back(parse_insert_literal(value));
2430  }
2431  }
2432  values_lists_.push_back(std::move(values_list));
2433  }
2434 }
InsertStmt(std::string *t, std::list< std::string * > *c)
Definition: ParserNode.h:2080
const std::string json_str(const rapidjson::Value &obj) noexcept
Definition: JsonAccessors.h:44
std::unique_ptr< std::string > table_
Definition: ParserNode.h:2096
ArrayLiteral * parse_insert_array_literal(const rapidjson::Value &array)
Literal * parse_insert_literal(const rapidjson::Value &literal)
std::list< std::unique_ptr< std::string > > column_list_
Definition: ParserNode.h:2097
#define CHECK(condition)
Definition: Logger.h:222
std::vector< std::unique_ptr< ValuesList > > values_lists_
Definition: ParserNode.h:2143

+ Here is the call graph for this function:

Parser::InsertValuesStmt::InsertValuesStmt ( std::string *  t,
std::list< std::string * > *  c,
std::list< Expr * > *  v 
)
inline

Definition at line 2126 of file ParserNode.h.

References UNREACHABLE.

2127  : InsertStmt(t, c) {
2128  UNREACHABLE() << "Legacy inserts should not be called anymore";
2129  }
InsertStmt(std::string *t, std::list< std::string * > *c)
Definition: ParserNode.h:2080
#define UNREACHABLE()
Definition: Logger.h:266

Member Function Documentation

void Parser::InsertValuesStmt::analyze ( const Catalog_Namespace::Catalog catalog,
Analyzer::Query query 
) const
overridevirtual

Implements Parser::InsertStmt.

Definition at line 2436 of file ParserNode.cpp.

References Parser::InsertStmt::analyze(), CHECK, CHECK_EQ, Parser::InsertStmt::column_list_, Geospatial::compress_coords(), Datum::doubleval, Analyzer::Query::get_result_col_list(), Analyzer::Query::get_result_table_id(), Analyzer::Query::get_values_lists(), Catalog_Namespace::Catalog::getAllColumnMetadataForTable(), Geospatial::GeoTypesFactory::getGeoColumns(), Catalog_Namespace::Catalog::getMetadataForColumn(), Datum::intval, is_null(), kARRAY, kCAST, kDOUBLE, kINT, kLINESTRING, kMULTIPOLYGON, kPOINT, kPOLYGON, kTINYINT, NULL_ARRAY_DOUBLE, NULL_DOUBLE, Datum::tinyintval, to_string(), and values_lists_.

Referenced by execute().

2437  {
2438  InsertStmt::analyze(catalog, query);
2439  size_t list_size = values_lists_[0]->get_value_list().size();
2440  if (!column_list_.empty()) {
2441  if (list_size != column_list_.size()) {
2442  throw std::runtime_error(
2443  "Numbers of columns and values don't match for the "
2444  "insert.");
2445  }
2446  } else {
2447  const auto tableId = query.get_result_table_id();
2448  const std::list<const ColumnDescriptor*> non_phys_cols =
2449  catalog.getAllColumnMetadataForTable(tableId, false, false, false);
2450  if (non_phys_cols.size() != list_size) {
2451  throw std::runtime_error(
2452  "Number of columns in table does not match the list of values given in the "
2453  "insert.");
2454  }
2455  }
2456  std::vector<const ColumnDescriptor*> cds;
2457  cds.reserve(query.get_result_col_list().size());
2458  for (auto id : query.get_result_col_list()) {
2459  const auto* cd = catalog.getMetadataForColumn(query.get_result_table_id(), id);
2460  CHECK(cd);
2461  cds.push_back(cd);
2462  }
2463  auto& query_values_lists = query.get_values_lists();
2464  query_values_lists.resize(values_lists_.size());
2465  for (size_t i = 0; i < values_lists_.size(); ++i) {
2466  const auto& values_list = values_lists_[i]->get_value_list();
2467  if (values_list.size() != list_size) {
2468  throw std::runtime_error(
2469  "Insert values lists should be of the same size. Expected: " +
2470  std::to_string(list_size) + ", Got: " + std::to_string(values_list.size()));
2471  }
2472  auto& query_values_list = query_values_lists[i];
2473  size_t cds_id = 0;
2474  for (auto& v : values_list) {
2475  auto e = v->analyze(catalog, query);
2476  const auto* cd = cds[cds_id];
2477  const auto& col_ti = cd->columnType;
2478  if (col_ti.get_notnull()) {
2479  auto c = std::dynamic_pointer_cast<Analyzer::Constant>(e);
2480  if (c != nullptr && c->get_is_null()) {
2481  throw std::runtime_error("Cannot insert NULL into column " + cd->columnName);
2482  }
2483  }
2484  e = e->add_cast(col_ti);
2485  query_values_list.emplace_back(new Analyzer::TargetEntry("", e, false));
2486  ++cds_id;
2487 
2488  if (col_ti.get_physical_cols() > 0) {
2489  CHECK(cd->columnType.is_geometry());
2490  auto c = dynamic_cast<const Analyzer::Constant*>(e.get());
2491  if (!c) {
2492  auto uoper = std::dynamic_pointer_cast<Analyzer::UOper>(e);
2493  if (uoper && uoper->get_optype() == kCAST) {
2494  c = dynamic_cast<const Analyzer::Constant*>(uoper->get_operand());
2495  }
2496  }
2497  bool is_null = false;
2498  std::string* geo_string{nullptr};
2499  if (c) {
2500  is_null = c->get_is_null();
2501  if (!is_null) {
2502  geo_string = c->get_constval().stringval;
2503  }
2504  }
2505  if (!is_null && !geo_string) {
2506  throw std::runtime_error("Expecting a WKT or WKB hex string for column " +
2507  cd->columnName);
2508  }
2509  std::vector<double> coords;
2510  std::vector<double> bounds;
2511  std::vector<int> ring_sizes;
2512  std::vector<int> poly_rings;
2513  int render_group =
2514  0; // @TODO simon.eves where to get render_group from in this context?!
2515  SQLTypeInfo import_ti{cd->columnType};
2516  if (!is_null) {
2518  *geo_string, import_ti, coords, bounds, ring_sizes, poly_rings)) {
2519  throw std::runtime_error("Cannot read geometry to insert into column " +
2520  cd->columnName);
2521  }
2522  if (coords.empty()) {
2523  // Importing from geo_string WKT resulted in empty coords: dealing with a NULL
2524  is_null = true;
2525  }
2526  if (cd->columnType.get_type() != import_ti.get_type()) {
2527  // allow POLYGON to be inserted into MULTIPOLYGON column
2528  if (!(import_ti.get_type() == SQLTypes::kPOLYGON &&
2529  cd->columnType.get_type() == SQLTypes::kMULTIPOLYGON)) {
2530  throw std::runtime_error(
2531  "Imported geometry doesn't match the type of column " + cd->columnName);
2532  }
2533  }
2534  } else {
2535  // Special case for NULL POINT, push NULL representation to coords
2536  if (cd->columnType.get_type() == kPOINT) {
2537  if (!coords.empty()) {
2538  throw std::runtime_error(
2539  "NULL POINT with unexpected coordinates in column " + cd->columnName);
2540  }
2541  coords.push_back(NULL_ARRAY_DOUBLE);
2542  coords.push_back(NULL_DOUBLE);
2543  }
2544  }
2545 
2546  // TODO: check if import SRID matches columns SRID, may need to transform before
2547  // inserting
2548 
2549  const auto* cd_coords = cds[cds_id];
2550  CHECK_EQ(cd_coords->columnType.get_type(), kARRAY);
2551  CHECK_EQ(cd_coords->columnType.get_subtype(), kTINYINT);
2552  std::list<std::shared_ptr<Analyzer::Expr>> value_exprs;
2553  if (!is_null || cd->columnType.get_type() == kPOINT) {
2554  auto compressed_coords = Geospatial::compress_coords(coords, col_ti);
2555  for (auto cc : compressed_coords) {
2556  Datum d;
2557  d.tinyintval = cc;
2558  auto e = makeExpr<Analyzer::Constant>(kTINYINT, false, d);
2559  value_exprs.push_back(e);
2560  }
2561  }
2562  query_values_list.emplace_back(new Analyzer::TargetEntry(
2563  "",
2564  makeExpr<Analyzer::Constant>(cd_coords->columnType, is_null, value_exprs),
2565  false));
2566  ++cds_id;
2567 
2568  if (cd->columnType.get_type() == kPOLYGON ||
2569  cd->columnType.get_type() == kMULTIPOLYGON) {
2570  // Put ring sizes array into separate physical column
2571  const auto* cd_ring_sizes = cds[cds_id];
2572  CHECK(cd_ring_sizes);
2573  CHECK_EQ(cd_ring_sizes->columnType.get_type(), kARRAY);
2574  CHECK_EQ(cd_ring_sizes->columnType.get_subtype(), kINT);
2575  std::list<std::shared_ptr<Analyzer::Expr>> value_exprs;
2576  if (!is_null) {
2577  for (auto c : ring_sizes) {
2578  Datum d;
2579  d.intval = c;
2580  auto e = makeExpr<Analyzer::Constant>(kINT, false, d);
2581  value_exprs.push_back(e);
2582  }
2583  }
2584  query_values_list.emplace_back(new Analyzer::TargetEntry(
2585  "",
2586  makeExpr<Analyzer::Constant>(
2587  cd_ring_sizes->columnType, is_null, value_exprs),
2588  false));
2589  ++cds_id;
2590 
2591  if (cd->columnType.get_type() == kMULTIPOLYGON) {
2592  // Put poly_rings array into separate physical column
2593  const auto* cd_poly_rings = cds[cds_id];
2594  CHECK(cd_poly_rings);
2595  CHECK_EQ(cd_poly_rings->columnType.get_type(), kARRAY);
2596  CHECK_EQ(cd_poly_rings->columnType.get_subtype(), kINT);
2597  std::list<std::shared_ptr<Analyzer::Expr>> value_exprs;
2598  if (!is_null) {
2599  for (auto c : poly_rings) {
2600  Datum d;
2601  d.intval = c;
2602  auto e = makeExpr<Analyzer::Constant>(kINT, false, d);
2603  value_exprs.push_back(e);
2604  }
2605  }
2606  query_values_list.emplace_back(new Analyzer::TargetEntry(
2607  "",
2608  makeExpr<Analyzer::Constant>(
2609  cd_poly_rings->columnType, is_null, value_exprs),
2610  false));
2611  ++cds_id;
2612  }
2613  }
2614 
2615  if (cd->columnType.get_type() == kLINESTRING ||
2616  cd->columnType.get_type() == kPOLYGON ||
2617  cd->columnType.get_type() == kMULTIPOLYGON) {
2618  const auto* cd_bounds = cds[cds_id];
2619  CHECK(cd_bounds);
2620  CHECK_EQ(cd_bounds->columnType.get_type(), kARRAY);
2621  CHECK_EQ(cd_bounds->columnType.get_subtype(), kDOUBLE);
2622  std::list<std::shared_ptr<Analyzer::Expr>> value_exprs;
2623  if (!is_null) {
2624  for (auto b : bounds) {
2625  Datum d;
2626  d.doubleval = b;
2627  auto e = makeExpr<Analyzer::Constant>(kDOUBLE, false, d);
2628  value_exprs.push_back(e);
2629  }
2630  }
2631  query_values_list.emplace_back(new Analyzer::TargetEntry(
2632  "",
2633  makeExpr<Analyzer::Constant>(cd_bounds->columnType, is_null, value_exprs),
2634  false));
2635  ++cds_id;
2636  }
2637 
2638  if (cd->columnType.get_type() == kPOLYGON ||
2639  cd->columnType.get_type() == kMULTIPOLYGON) {
2640  // Put render group into separate physical column
2641  const auto* cd_render_group = cds[cds_id];
2642  CHECK(cd_render_group);
2643  CHECK_EQ(cd_render_group->columnType.get_type(), kINT);
2644  Datum d;
2645  d.intval = render_group;
2646  query_values_list.emplace_back(new Analyzer::TargetEntry(
2647  "",
2648  makeExpr<Analyzer::Constant>(cd_render_group->columnType, is_null, d),
2649  false));
2650  ++cds_id;
2651  }
2652  }
2653  }
2654  }
2655 }
int8_t tinyintval
Definition: sqltypes.h:212
#define CHECK_EQ(x, y)
Definition: Logger.h:230
#define NULL_DOUBLE
Definition: Analyzer.h:2387
const std::vector< std::vector< std::shared_ptr< TargetEntry > > > & get_values_lists() const
Definition: Analyzer.h:2436
Definition: sqldefs.h:48
void analyze(const Catalog_Namespace::Catalog &catalog, Analyzer::Query &query) const override=0
int32_t intval
Definition: sqltypes.h:214
std::string to_string(char const *&&v)
std::vector< uint8_t > compress_coords(const std::vector< double > &coords, const SQLTypeInfo &ti)
Definition: Compression.cpp:52
CONSTEXPR DEVICE bool is_null(const T &value)
const ColumnDescriptor * getMetadataForColumn(int tableId, const std::string &colName) const
int get_result_table_id() const
Definition: Analyzer.h:2452
static bool getGeoColumns(const std::string &wkt_or_wkb_hex, SQLTypeInfo &ti, std::vector< double > &coords, std::vector< double > &bounds, std::vector< int > &ring_sizes, std::vector< int > &poly_rings, const bool promote_poly_to_mpoly=false)
Definition: Types.cpp:937
std::list< const ColumnDescriptor * > getAllColumnMetadataForTable(const int tableId, const bool fetchSystemColumns, const bool fetchVirtualColumns, const bool fetchPhysicalColumns) const
Returns a list of pointers to constant ColumnDescriptor structs for all the columns from a particular...
Definition: Catalog.cpp:1939
std::list< std::unique_ptr< std::string > > column_list_
Definition: ParserNode.h:2097
#define NULL_ARRAY_DOUBLE
#define CHECK(condition)
Definition: Logger.h:222
std::vector< std::unique_ptr< ValuesList > > values_lists_
Definition: ParserNode.h:2143
Definition: sqltypes.h:45
const std::list< int > & get_result_col_list() const
Definition: Analyzer.h:2453
double doubleval
Definition: sqltypes.h:217

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void Parser::InsertValuesStmt::execute ( const Catalog_Namespace::SessionInfo session,
bool  read_only_mode 
)

Definition at line 2657 of file ParserNode.cpp.

References analyze(), CHECK, Catalog_Namespace::SessionInfo::checkDBAccessPrivileges(), Fragmenter_Namespace::InsertDataLoader::InsertConnector::checkpoint(), logger::ERROR, legacylockmgr::ExecutorOuterLock, Catalog_Namespace::SessionInfo::getCatalog(), Executor::getExecutor(), legacylockmgr::LockMgr< MutexType, KeyType >::getMutex(), lockmgr::TableLockMgrImpl< InsertDataLockMgr >::getWriteLockForTable(), AccessPrivileges::INSERT_INTO_TABLE, leafs_connector_, LOG, Fragmenter_Namespace::InsertDataLoader::InsertConnector::rollback(), Parser::InsertStmt::table_, TableDBObjectType, Executor::UNITARY_EXECUTOR_ID, and foreign_storage::validate_non_foreign_table_write().

Referenced by heavydb.cursor.Cursor::executemany().

2658  {
2659  if (read_only_mode) {
2660  throw std::runtime_error("INSERT values invalid in read only mode.");
2661  }
2662  auto execute_read_lock = heavyai::shared_lock<heavyai::shared_mutex>(
2665  auto& catalog = session.getCatalog();
2666  const auto td_with_lock =
2668  catalog, *table_);
2671  *table_)) {
2672  throw std::runtime_error("User has no insert privileges on " + *table_ + ".");
2673  }
2674  Analyzer::Query query;
2675  analyze(catalog, query);
2676 
2677  // Take an insert data write lock, which prevents concurrent inserts.
2678  const auto insert_data_lock =
2680 
2681  // NOTE(max): we do the same checks as below just a few calls earlier in analyze().
2682  // Do we keep those intentionally to make sure nothing changed in between w/o
2683  // catalog locks or is it just a duplicate work?
2684  auto td = td_with_lock();
2685  CHECK(td);
2686  if (td->isView) {
2687  throw std::runtime_error("Singleton inserts on views is not supported.");
2688  }
2690 
2692  RelAlgExecutor ra_executor(executor.get(), catalog);
2693 
2695  if (!leafs_connector_) {
2696  leafs_connector_ = &local_connector;
2697  }
2699  try {
2700  ra_executor.executeSimpleInsert(query, insert_data_loader, session);
2701  } catch (...) {
2702  try {
2703  leafs_connector_->rollback(session, td->tableId);
2704  } catch (std::exception& e) {
2705  LOG(ERROR) << "An error occurred during insert rollback attempt. Table id: "
2706  << td->tableId << ", Error: " << e.what();
2707  }
2708  throw;
2709  }
2710  if (!td->isTemporaryTable()) {
2711  leafs_connector_->checkpoint(session, td->tableId);
2712  }
2713 }
void validate_non_foreign_table_write(const TableDescriptor *table_descriptor)
Definition: FsiUtils.h:22
#define LOG(tag)
Definition: Logger.h:216
static WriteLock getWriteLockForTable(const Catalog_Namespace::Catalog &cat, const std::string &table_name)
Definition: LockMgrImpl.h:155
static const AccessPrivileges INSERT_INTO_TABLE
Definition: DBObject.h:161
Fragmenter_Namespace::InsertDataLoader::InsertConnector * leafs_connector_
Definition: ParserNode.h:2140
std::unique_ptr< std::string > table_
Definition: ParserNode.h:2096
std::shared_lock< T > shared_lock
static std::shared_ptr< Executor > getExecutor(const ExecutorId id, const std::string &debug_dir="", const std::string &debug_file="", const SystemParameters &system_parameters=SystemParameters())
Definition: Execute.cpp:483
virtual void checkpoint(const Catalog_Namespace::SessionInfo &parent_session_info, int tableId)=0
Catalog & getCatalog() const
Definition: SessionInfo.h:65
static std::shared_ptr< MutexType > getMutex(const LockType lockType, const KeyType &key)
Definition: LegacyLockMgr.h:51
#define CHECK(condition)
Definition: Logger.h:222
virtual void rollback(const Catalog_Namespace::SessionInfo &parent_session_info, int tableId)=0
bool checkDBAccessPrivileges(const DBObjectType &permissionType, const AccessPrivileges &privs, const std::string &objectName="") const
Definition: SessionInfo.cpp:24
void analyze(const Catalog_Namespace::Catalog &catalog, Analyzer::Query &query) const override
static const ExecutorId UNITARY_EXECUTOR_ID
Definition: Execute.h:376

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

const std::vector<std::unique_ptr<ValuesList> >& Parser::InsertValuesStmt::get_value_lists ( ) const
inline

Definition at line 2131 of file ParserNode.h.

References values_lists_.

2131  {
2132  return values_lists_;
2133  }
std::vector< std::unique_ptr< ValuesList > > values_lists_
Definition: ParserNode.h:2143

Member Data Documentation

Fragmenter_Namespace::InsertDataLoader::InsertConnector* Parser::InsertValuesStmt::leafs_connector_ = nullptr

Definition at line 2140 of file ParserNode.h.

Referenced by execute().

std::vector<std::unique_ptr<ValuesList> > Parser::InsertValuesStmt::values_lists_
private

Definition at line 2143 of file ParserNode.h.

Referenced by analyze(), get_value_lists(), and InsertValuesStmt().


The documentation for this class was generated from the following files: