OmniSciDB  a5dc49c757
 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 2455 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_.

2457  : InsertStmt(nullptr, nullptr) {
2458  CHECK(payload.HasMember("name"));
2459  table_ = std::make_unique<std::string>(json_str(payload["name"]));
2460 
2461  if (payload.HasMember("columns")) {
2462  CHECK(payload["columns"].IsArray());
2463  for (auto& column : payload["columns"].GetArray()) {
2464  std::string s = json_str(column);
2465  column_list_.emplace_back(std::make_unique<std::string>(s));
2466  }
2467  }
2468 
2469  CHECK(payload.HasMember("values") && payload["values"].IsArray());
2470  auto tuples = payload["values"].GetArray();
2471  if (tuples.Empty()) {
2472  throw std::runtime_error("Values statement cannot be empty");
2473  }
2474  values_lists_.reserve(tuples.Size());
2475  int column_offset = 0;
2476  try {
2477  for (const auto& json_tuple : tuples) {
2478  auto values_list = std::make_unique<ValuesList>();
2479  CHECK(json_tuple.IsArray());
2480  auto tuple = json_tuple.GetArray();
2481  column_offset = 0;
2482  for (const auto& value : tuple) {
2483  CHECK(value.IsObject());
2484  if (value.HasMember("array")) {
2485  values_list->push_back(parse_insert_array_literal(value["array"]));
2486  } else {
2487  values_list->push_back(parse_insert_literal(value));
2488  }
2489  ++column_offset;
2490  }
2491  values_lists_.push_back(std::move(values_list));
2492  }
2493  } catch (std::out_of_range const& e) {
2494  auto* td = catalog.getMetadataForTable(*table_, false);
2495  CHECK(td);
2496  auto cds = catalog.getAllColumnMetadataForTable(td->tableId, false, false, false);
2497  auto target_col_iter = cds.begin();
2498  std::advance(target_col_iter, column_offset);
2499  auto* cd = *target_col_iter;
2500  CHECK(cd);
2501  auto const col_identifier = td->tableName + "." + cd->columnName;
2502  throw std::runtime_error(
2503  "Detected an out-of-range exception when inserting a value into column \"" +
2504  col_identifier + "\"");
2505  }
2506 }
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:2175
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 2508 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().

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

+ 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 2718 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().

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