OmniSciDB  72c90bc290
 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 Catalog_Namespace::Catalog &catalog, 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

std::unique_ptr
< Fragmenter_Namespace::InsertDataLoader::InsertConnector
leafs_connector_
 

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 2119 of file ParserNode.h.

Constructor & Destructor Documentation

Parser::InsertValuesStmt::InsertValuesStmt ( const Catalog_Namespace::Catalog catalog,
const rapidjson::Value &  payload 
)

Definition at line 2445 of file ParserNode.cpp.

References CHECK, Parser::InsertStmt::column_list_, Catalog_Namespace::Catalog::getAllColumnMetadataForTable(), Catalog_Namespace::Catalog::getMetadataForTable(), 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_.

2447  : InsertStmt(nullptr, nullptr) {
2448  CHECK(payload.HasMember("name"));
2449  table_ = std::make_unique<std::string>(json_str(payload["name"]));
2450 
2451  if (payload.HasMember("columns")) {
2452  CHECK(payload["columns"].IsArray());
2453  for (auto& column : payload["columns"].GetArray()) {
2454  std::string s = json_str(column);
2455  column_list_.emplace_back(std::make_unique<std::string>(s));
2456  }
2457  }
2458 
2459  CHECK(payload.HasMember("values") && payload["values"].IsArray());
2460  auto tuples = payload["values"].GetArray();
2461  if (tuples.Empty()) {
2462  throw std::runtime_error("Values statement cannot be empty");
2463  }
2464  values_lists_.reserve(tuples.Size());
2465  int column_offset = 0;
2466  try {
2467  for (const auto& json_tuple : tuples) {
2468  auto values_list = std::make_unique<ValuesList>();
2469  CHECK(json_tuple.IsArray());
2470  auto tuple = json_tuple.GetArray();
2471  column_offset = 0;
2472  for (const auto& value : tuple) {
2473  CHECK(value.IsObject());
2474  if (value.HasMember("array")) {
2475  values_list->push_back(parse_insert_array_literal(value["array"]));
2476  } else {
2477  values_list->push_back(parse_insert_literal(value));
2478  }
2479  ++column_offset;
2480  }
2481  values_lists_.push_back(std::move(values_list));
2482  }
2483  } catch (std::out_of_range const& e) {
2484  auto* td = catalog.getMetadataForTable(*table_, false);
2485  CHECK(td);
2486  auto cds = catalog.getAllColumnMetadataForTable(td->tableId, false, false, false);
2487  auto target_col_iter = cds.begin();
2488  std::advance(target_col_iter, column_offset);
2489  auto* cd = *target_col_iter;
2490  CHECK(cd);
2491  auto const col_identifier = td->tableName + "." + cd->columnName;
2492  throw std::runtime_error(
2493  "Detected an out-of-range exception when inserting a value into column \"" +
2494  col_identifier + "\"");
2495  }
2496 }
InsertStmt(std::string *t, std::list< std::string * > *c)
Definition: ParserNode.h:2076
const std::string json_str(const rapidjson::Value &obj) noexcept
Definition: JsonAccessors.h:46
std::unique_ptr< std::string > table_
Definition: ParserNode.h:2092
ArrayLiteral * parse_insert_array_literal(const rapidjson::Value &array)
Literal * parse_insert_literal(const rapidjson::Value &literal)
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:2172
std::list< std::unique_ptr< std::string > > column_list_
Definition: ParserNode.h:2093
#define CHECK(condition)
Definition: Logger.h:291
std::vector< std::unique_ptr< ValuesList > > values_lists_
Definition: ParserNode.h:2141
const TableDescriptor * getMetadataForTable(const std::string &tableName, const bool populateFragmenter=true) const
Returns a pointer to a const TableDescriptor struct matching the provided tableName.

+ 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 2123 of file ParserNode.h.

References UNREACHABLE.

2124  : InsertStmt(t, c) {
2125  UNREACHABLE() << "Legacy inserts should not be called anymore";
2126  }
InsertStmt(std::string *t, std::list< std::string * > *c)
Definition: ParserNode.h:2076
#define UNREACHABLE()
Definition: Logger.h:338

Member Function Documentation

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

Implements Parser::InsertStmt.

Definition at line 2498 of file ParserNode.cpp.

References Parser::InsertStmt::analyze(), CHECK, CHECK_EQ, Parser::InsertStmt::column_list_, Geospatial::compress_coords(), Datum::doubleval, geo_promoted_type_match(), 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, kMULTILINESTRING, kMULTIPOINT, kMULTIPOLYGON, kPOINT, kPOLYGON, kTINYINT, NULL_ARRAY_DOUBLE, NULL_DOUBLE, Datum::tinyintval, to_string(), and values_lists_.

Referenced by execute().

2499  {
2500  InsertStmt::analyze(catalog, query);
2501  size_t list_size = values_lists_[0]->get_value_list().size();
2502  if (!column_list_.empty()) {
2503  if (list_size != column_list_.size()) {
2504  throw std::runtime_error(
2505  "Numbers of columns and values don't match for the "
2506  "insert.");
2507  }
2508  } else {
2509  const auto tableId = query.get_result_table_id();
2510  const std::list<const ColumnDescriptor*> non_phys_cols =
2511  catalog.getAllColumnMetadataForTable(tableId, false, false, false);
2512  if (non_phys_cols.size() != list_size) {
2513  throw std::runtime_error(
2514  "Number of columns in table does not match the list of values given in the "
2515  "insert.");
2516  }
2517  }
2518  std::vector<const ColumnDescriptor*> cds;
2519  cds.reserve(query.get_result_col_list().size());
2520  for (auto id : query.get_result_col_list()) {
2521  const auto* cd = catalog.getMetadataForColumn(query.get_result_table_id(), id);
2522  CHECK(cd);
2523  cds.push_back(cd);
2524  }
2525  auto& query_values_lists = query.get_values_lists();
2526  query_values_lists.resize(values_lists_.size());
2527  for (size_t i = 0; i < values_lists_.size(); ++i) {
2528  const auto& values_list = values_lists_[i]->get_value_list();
2529  if (values_list.size() != list_size) {
2530  throw std::runtime_error(
2531  "Insert values lists should be of the same size. Expected: " +
2532  std::to_string(list_size) + ", Got: " + std::to_string(values_list.size()));
2533  }
2534  auto& query_values_list = query_values_lists[i];
2535  size_t cds_id = 0;
2536  for (auto& v : values_list) {
2537  auto e = v->analyze(catalog, query);
2538  const auto* cd = cds[cds_id];
2539  const auto& col_ti = cd->columnType;
2540  if (col_ti.get_notnull()) {
2541  auto c = std::dynamic_pointer_cast<Analyzer::Constant>(e);
2542  if (c != nullptr && c->get_is_null()) {
2543  throw std::runtime_error("Cannot insert NULL into column " + cd->columnName);
2544  }
2545  }
2546  e = e->add_cast(col_ti);
2547  query_values_list.emplace_back(new Analyzer::TargetEntry("", e, false));
2548  ++cds_id;
2549 
2550  if (col_ti.get_physical_cols() > 0) {
2551  CHECK(cd->columnType.is_geometry());
2552  auto c = dynamic_cast<const Analyzer::Constant*>(e.get());
2553  if (!c) {
2554  auto uoper = std::dynamic_pointer_cast<Analyzer::UOper>(e);
2555  if (uoper && uoper->get_optype() == kCAST) {
2556  c = dynamic_cast<const Analyzer::Constant*>(uoper->get_operand());
2557  }
2558  }
2559  bool is_null = false;
2560  std::string* geo_string{nullptr};
2561  if (c) {
2562  is_null = c->get_is_null();
2563  if (!is_null) {
2564  geo_string = c->get_constval().stringval;
2565  }
2566  }
2567  if (!is_null && !geo_string) {
2568  throw std::runtime_error("Expecting a WKT or WKB hex string for column " +
2569  cd->columnName);
2570  }
2571  std::vector<double> coords;
2572  std::vector<double> bounds;
2573  std::vector<int> ring_sizes;
2574  std::vector<int> poly_rings;
2575  SQLTypeInfo import_ti{cd->columnType};
2576  if (!is_null) {
2577  const bool validate_with_geos_if_available = false;
2579  *geo_string,
2580  import_ti,
2581  coords,
2582  bounds,
2583  ring_sizes,
2584  poly_rings,
2585  validate_with_geos_if_available)) {
2586  throw std::runtime_error("Cannot read geometry to insert into column " +
2587  cd->columnName);
2588  }
2589  if (coords.empty()) {
2590  // Importing from geo_string WKT resulted in empty coords: dealing with a NULL
2591  is_null = true;
2592  }
2593  if (!geo_promoted_type_match(import_ti.get_type(), cd->columnType.get_type())) {
2594  throw std::runtime_error(
2595  "Imported geometry doesn't match the type of column " + cd->columnName);
2596  }
2597  } else {
2598  // Special case for NULL POINT, push NULL representation to coords
2599  if (cd->columnType.get_type() == kPOINT) {
2600  if (!coords.empty()) {
2601  throw std::runtime_error(
2602  "NULL POINT with unexpected coordinates in column " + cd->columnName);
2603  }
2604  coords.push_back(NULL_ARRAY_DOUBLE);
2605  coords.push_back(NULL_DOUBLE);
2606  }
2607  }
2608 
2609  // TODO: check if import SRID matches columns SRID, may need to transform before
2610  // inserting
2611 
2612  const auto* cd_coords = cds[cds_id];
2613  CHECK_EQ(cd_coords->columnType.get_type(), kARRAY);
2614  CHECK_EQ(cd_coords->columnType.get_subtype(), kTINYINT);
2615  std::list<std::shared_ptr<Analyzer::Expr>> value_exprs;
2616  if (!is_null || cd->columnType.get_type() == kPOINT) {
2617  auto compressed_coords = Geospatial::compress_coords(coords, col_ti);
2618  for (auto cc : compressed_coords) {
2619  Datum d;
2620  d.tinyintval = cc;
2621  auto e = makeExpr<Analyzer::Constant>(kTINYINT, false, d);
2622  value_exprs.push_back(e);
2623  }
2624  }
2625  query_values_list.emplace_back(new Analyzer::TargetEntry(
2626  "",
2627  makeExpr<Analyzer::Constant>(cd_coords->columnType, is_null, value_exprs),
2628  false));
2629  ++cds_id;
2630 
2631  if (cd->columnType.get_type() == kMULTILINESTRING ||
2632  cd->columnType.get_type() == kPOLYGON ||
2633  cd->columnType.get_type() == kMULTIPOLYGON) {
2634  // Put [linest]ring sizes array into separate physical column
2635  const auto* cd_ring_sizes = cds[cds_id];
2636  CHECK(cd_ring_sizes);
2637  CHECK_EQ(cd_ring_sizes->columnType.get_type(), kARRAY);
2638  CHECK_EQ(cd_ring_sizes->columnType.get_subtype(), kINT);
2639  std::list<std::shared_ptr<Analyzer::Expr>> value_exprs;
2640  if (!is_null) {
2641  for (auto c : ring_sizes) {
2642  Datum d;
2643  d.intval = c;
2644  auto e = makeExpr<Analyzer::Constant>(kINT, false, d);
2645  value_exprs.push_back(e);
2646  }
2647  }
2648  query_values_list.emplace_back(new Analyzer::TargetEntry(
2649  "",
2650  makeExpr<Analyzer::Constant>(
2651  cd_ring_sizes->columnType, is_null, value_exprs),
2652  false));
2653  ++cds_id;
2654 
2655  if (cd->columnType.get_type() == kMULTIPOLYGON) {
2656  // Put poly_rings array into separate physical column
2657  const auto* cd_poly_rings = cds[cds_id];
2658  CHECK(cd_poly_rings);
2659  CHECK_EQ(cd_poly_rings->columnType.get_type(), kARRAY);
2660  CHECK_EQ(cd_poly_rings->columnType.get_subtype(), kINT);
2661  std::list<std::shared_ptr<Analyzer::Expr>> value_exprs;
2662  if (!is_null) {
2663  for (auto c : poly_rings) {
2664  Datum d;
2665  d.intval = c;
2666  auto e = makeExpr<Analyzer::Constant>(kINT, false, d);
2667  value_exprs.push_back(e);
2668  }
2669  }
2670  query_values_list.emplace_back(new Analyzer::TargetEntry(
2671  "",
2672  makeExpr<Analyzer::Constant>(
2673  cd_poly_rings->columnType, is_null, value_exprs),
2674  false));
2675  ++cds_id;
2676  }
2677  }
2678 
2679  if (cd->columnType.get_type() == kMULTIPOINT ||
2680  cd->columnType.get_type() == kLINESTRING ||
2681  cd->columnType.get_type() == kMULTILINESTRING ||
2682  cd->columnType.get_type() == kPOLYGON ||
2683  cd->columnType.get_type() == kMULTIPOLYGON) {
2684  const auto* cd_bounds = cds[cds_id];
2685  CHECK(cd_bounds);
2686  CHECK_EQ(cd_bounds->columnType.get_type(), kARRAY);
2687  CHECK_EQ(cd_bounds->columnType.get_subtype(), kDOUBLE);
2688  std::list<std::shared_ptr<Analyzer::Expr>> value_exprs;
2689  if (!is_null) {
2690  for (auto b : bounds) {
2691  Datum d;
2692  d.doubleval = b;
2693  auto e = makeExpr<Analyzer::Constant>(kDOUBLE, false, d);
2694  value_exprs.push_back(e);
2695  }
2696  }
2697  query_values_list.emplace_back(new Analyzer::TargetEntry(
2698  "",
2699  makeExpr<Analyzer::Constant>(cd_bounds->columnType, is_null, value_exprs),
2700  false));
2701  ++cds_id;
2702  }
2703  }
2704  }
2705  }
2706 }
int8_t tinyintval
Definition: Datum.h:71
bool geo_promoted_type_match(const SQLTypes a, const SQLTypes b)
Definition: sqltypes.h:2029
#define CHECK_EQ(x, y)
Definition: Logger.h:301
#define NULL_DOUBLE
Definition: Analyzer.h:2977
const std::vector< std::vector< std::shared_ptr< TargetEntry > > > & get_values_lists() const
Definition: Analyzer.h:3026
Definition: sqldefs.h:48
void analyze(const Catalog_Namespace::Catalog &catalog, Analyzer::Query &query) const override=0
int32_t intval
Definition: Datum.h:73
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
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 validate_with_geos_if_available)
Definition: Types.cpp:1121
int get_result_table_id() const
Definition: Analyzer.h:3042
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:2172
std::list< std::unique_ptr< std::string > > column_list_
Definition: ParserNode.h:2093
#define NULL_ARRAY_DOUBLE
#define CHECK(condition)
Definition: Logger.h:291
std::vector< std::unique_ptr< ValuesList > > values_lists_
Definition: ParserNode.h:2141
Definition: sqltypes.h:72
const std::list< int > & get_result_col_list() const
Definition: Analyzer.h:3043
Definition: Datum.h:69
double doubleval
Definition: Datum.h:76

+ 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 2708 of file ParserNode.cpp.

References analyze(), CHECK, Catalog_Namespace::SessionInfo::checkDBAccessPrivileges(), logger::ERROR, Catalog_Namespace::SessionInfo::getCatalog(), legacylockmgr::getExecuteReadLock(), Executor::getExecutor(), lockmgr::TableLockMgrImpl< T >::getWriteLockForTable(), AccessPrivileges::INSERT_INTO_TABLE, leafs_connector_, LOG, Parser::InsertStmt::table_, TableDBObjectType, Executor::UNITARY_EXECUTOR_ID, and foreign_storage::validate_non_foreign_table_write().

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

2709  {
2710  if (read_only_mode) {
2711  throw std::runtime_error("INSERT values invalid in read only mode.");
2712  }
2713  auto execute_read_lock = legacylockmgr::getExecuteReadLock();
2714  auto& catalog = session.getCatalog();
2715  const auto td_with_lock =
2717  catalog, *table_);
2720  *table_)) {
2721  throw std::runtime_error("User has no insert privileges on " + *table_ + ".");
2722  }
2723  Analyzer::Query query;
2724  analyze(catalog, query);
2725 
2726  // Take an insert data write lock, which prevents concurrent inserts.
2727  const auto insert_data_lock =
2729 
2730  // NOTE(max): we do the same checks as below just a few calls earlier in analyze().
2731  // Do we keep those intentionally to make sure nothing changed in between w/o
2732  // catalog locks or is it just a duplicate work?
2733  auto td = td_with_lock();
2734  CHECK(td);
2735  if (td->isView) {
2736  throw std::runtime_error("Singleton inserts on views is not supported.");
2737  }
2739 
2741  RelAlgExecutor ra_executor(executor.get());
2742 
2743  if (!leafs_connector_) {
2744  leafs_connector_ = std::make_unique<Fragmenter_Namespace::LocalInsertConnector>();
2745  }
2747  try {
2748  ra_executor.executeSimpleInsert(query, insert_data_loader, session);
2749  } catch (...) {
2750  try {
2751  leafs_connector_->rollback(session, td->tableId);
2752  } catch (std::exception& e) {
2753  LOG(ERROR) << "An error occurred during insert rollback attempt. Table id: "
2754  << td->tableId << ", Error: " << e.what();
2755  }
2756  throw;
2757  }
2758  if (!td->isTemporaryTable()) {
2759  leafs_connector_->checkpoint(session, td->tableId);
2760  }
2761 }
void validate_non_foreign_table_write(const TableDescriptor *table_descriptor)
Definition: FsiUtils.h:22
auto getExecuteReadLock()
#define LOG(tag)
Definition: Logger.h:285
static WriteLock getWriteLockForTable(const Catalog_Namespace::Catalog &cat, const std::string &table_name)
Definition: LockMgrImpl.h:225
static const AccessPrivileges INSERT_INTO_TABLE
Definition: DBObject.h:161
std::unique_ptr< std::string > table_
Definition: ParserNode.h:2092
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:509
std::unique_ptr< Fragmenter_Namespace::InsertDataLoader::InsertConnector > leafs_connector_
Definition: ParserNode.h:2138
Catalog & getCatalog() const
Definition: SessionInfo.h:75
#define CHECK(condition)
Definition: Logger.h:291
static constexpr ExecutorId UNITARY_EXECUTOR_ID
Definition: Execute.h:423
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

+ 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 2128 of file ParserNode.h.

References values_lists_.

2128  {
2129  return values_lists_;
2130  }
std::vector< std::unique_ptr< ValuesList > > values_lists_
Definition: ParserNode.h:2141

Member Data Documentation

std::unique_ptr<Fragmenter_Namespace::InsertDataLoader::InsertConnector> Parser::InsertValuesStmt::leafs_connector_

Definition at line 2138 of file ParserNode.h.

Referenced by execute().

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

Definition at line 2141 of file ParserNode.h.

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


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