6060#include "../jrd/vio_proto.h"
6161#include "../jrd/idx_proto.h"
6262#include "../dsql/ddl_proto.h"
63+ #include "../dsql/dsql_proto.h"
6364#include "../dsql/errd_proto.h"
6465#include "../dsql/gen_proto.h"
6566#include "../dsql/make_proto.h"
@@ -9657,6 +9658,10 @@ string CreateRelationNode::internalPrint(NodePrinter& printer) const
96579658 NODE_PRINT(printer, externalFile);
96589659 NODE_PRINT(printer, tempFlag);
96599660 NODE_PRINT(printer, tempRowsFlag);
9661+ NODE_PRINT(printer, queryColumns);
9662+ NODE_PRINT(printer, querySelectExpr);
9663+ NODE_PRINT(printer, querySource);
9664+ NODE_PRINT(printer, withData);
96609665
96619666 return "CreateRelationNode";
96629667}
@@ -9680,6 +9685,9 @@ void CreateRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat
96809685 if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, name, obj_relation))
96819686 return;
96829687
9688+ if (querySelectExpr)
9689+ defineQueryColumns(tdbb, dsqlScratch);
9690+
96839691 saveRelation(tdbb, dsqlScratch, name, false, true);
96849692
96859693 if (externalFile)
@@ -9712,6 +9720,9 @@ void CreateRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat
97129720 // Update DSQL cache
97139721 METD_drop_relation(transaction, name);
97149722
9723+ if (withData)
9724+ executeInsert(tdbb, dsqlScratch, transaction);
9725+
97159726 return;
97169727 }
97179728
@@ -9933,9 +9944,190 @@ void CreateRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat
99339944 // Update DSQL cache
99349945 METD_drop_relation(transaction, name);
99359946
9947+ if (withData)
9948+ executeInsert(tdbb, dsqlScratch, transaction);
9949+
99369950 savePoint.release(); // everything is ok
99379951}
99389952
9953+ void CreateRelationNode::defineQueryColumns(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch)
9954+ {
9955+ fb_assert(querySelectExpr);
9956+
9957+ dsqlScratch->resetContextStack();
9958+ dsqlScratch->unionContext.clear();
9959+ dsqlScratch->derivedContext.clear();
9960+
9961+ const auto rse = PASS1_rse(dsqlScratch, querySelectExpr);
9962+ const auto items = rse->dsqlSelectList;
9963+
9964+ if (queryColumns && queryColumns->items.getCount() != items->items.getCount())
9965+ {
9966+ status_exception::raise(
9967+ Arg::Gds(isc_sqlerr) << Arg::Num(-607) <<
9968+ Arg::Gds(isc_dsql_command_err) <<
9969+ Arg::Gds(isc_num_field_err));
9970+ }
9971+
9972+ ObjectsArray<MetaName> names;
9973+ FB_SIZE_T position = 0;
9974+
9975+ for (auto item : items->items)
9976+ {
9977+ MetaName fieldName;
9978+
9979+ if (queryColumns)
9980+ fieldName = nodeAs<FieldNode>(queryColumns->items[position])->dsqlName;
9981+ else
9982+ {
9983+ const ValueExprNode* nameNode = item;
9984+ const char* aliasName = nullptr;
9985+
9986+ while (nodeIs<DsqlAliasNode>(nameNode) || nodeIs<DerivedFieldNode>(nameNode) ||
9987+ nodeIs<DsqlMapNode>(nameNode) || nodeAs<PackageReferenceNode>(nameNode))
9988+ {
9989+ if (const auto aliasNode = nodeAs<DsqlAliasNode>(nameNode))
9990+ {
9991+ if (!aliasName)
9992+ aliasName = aliasNode->name.c_str();
9993+
9994+ nameNode = aliasNode->value;
9995+ }
9996+ else if (const auto mapNode = nodeAs<DsqlMapNode>(nameNode))
9997+ nameNode = mapNode->map->map_node;
9998+ else if (const auto derivedField = nodeAs<DerivedFieldNode>(nameNode))
9999+ {
10000+ if (!aliasName)
10001+ aliasName = derivedField->name.c_str();
10002+
10003+ nameNode = derivedField->value;
10004+ }
10005+ else if (const auto referenceNode = nodeAs<PackageReferenceNode>(nameNode))
10006+ {
10007+ if (!aliasName)
10008+ aliasName = referenceNode->getName();
10009+
10010+ nameNode = nullptr;
10011+ }
10012+ }
10013+
10014+ if (aliasName)
10015+ fieldName = aliasName;
10016+ else if (const auto fieldNode = nodeAs<FieldNode>(nameNode))
10017+ fieldName = fieldNode->dsqlField->fld_name;
10018+ else
10019+ {
10020+ status_exception::raise(
10021+ Arg::Gds(isc_sqlerr) << Arg::Num(-607) <<
10022+ Arg::Gds(isc_dsql_command_err) <<
10023+ Arg::Gds(isc_specify_field_err));
10024+ }
10025+ }
10026+
10027+ for (const auto& name : names)
10028+ {
10029+ if (name == fieldName)
10030+ {
10031+ status_exception::raise(
10032+ Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
10033+ Arg::Gds(isc_dsql_command_err) <<
10034+ Arg::Gds(isc_dsql_col_more_than_once_view) << Arg::Str(fieldName.c_str()));
10035+ }
10036+ }
10037+
10038+ names.add() = fieldName;
10039+
10040+ dsc desc;
10041+ DsqlDescMaker::fromNode(dsqlScratch, &desc, item);
10042+
10043+ if (!desc.dsc_dtype)
10044+ {
10045+ status_exception::raise(
10046+ Arg::Gds(isc_sqlerr) << Arg::Num(-607) <<
10047+ Arg::Gds(isc_dsql_command_err) <<
10048+ Arg::Gds(isc_dsql_datatype_err));
10049+ }
10050+
10051+ auto clause = FB_NEW_POOL(dsqlScratch->getPool()) AddColumnClause(dsqlScratch->getPool());
10052+ clause->field = FB_NEW_POOL(dsqlScratch->getPool()) dsql_fld(dsqlScratch->getPool());
10053+
10054+ auto field = clause->field;
10055+ field->fld_name = fieldName;
10056+ field->dtype = desc.dsc_dtype;
10057+ field->length = desc.dsc_length;
10058+ field->scale = desc.dsc_scale;
10059+ field->subType = desc.dsc_sub_type;
10060+
10061+ if (desc.dsc_flags & DSC_nullable)
10062+ field->flags |= FLD_nullable;
10063+
10064+ if (desc.isText() || (desc.isBlob() && desc.getBlobSubType() == isc_blob_text))
10065+ {
10066+ field->charSetId = desc.getCharSet();
10067+ field->collationId = desc.getCollation();
10068+ }
10069+
10070+ if (desc.isText())
10071+ {
10072+ const USHORT adjust = (desc.dsc_dtype == dtype_varying) ? sizeof(USHORT) : 0;
10073+ const USHORT bpc = METD_get_charset_bpc(dsqlScratch->getTransaction(), field->charSetId.value_or(CS_NONE));
10074+ field->charLength = (field->length - adjust) / bpc;
10075+ }
10076+ else if (desc.isBlob())
10077+ field->segLength = 80;
10078+
10079+ field->setExactPrecision();
10080+ clauses.add(clause);
10081+
10082+ ++position;
10083+ }
10084+
10085+ dsqlScratch->resetContextStack();
10086+ dsqlScratch->unionContext.clear();
10087+ dsqlScratch->derivedContext.clear();
10088+ }
10089+
10090+ void CreateRelationNode::executeInsert(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
10091+ jrd_tra* transaction)
10092+ {
10093+ string sql;
10094+ sql.printf("insert into %s (", name.toQuotedString().c_str());
10095+
10096+ bool first = true;
10097+
10098+ for (const auto& clause : clauses)
10099+ {
10100+ if (clause->type != Clause::TYPE_ADD_COLUMN)
10101+ continue;
10102+
10103+ const auto addColumnClause = static_cast<const AddColumnClause*>(clause.getObject());
10104+
10105+ if (!first)
10106+ sql += ", ";
10107+
10108+ first = false;
10109+ sql += addColumnClause->field->fld_name.toQuotedString();
10110+ }
10111+
10112+ sql += ") ";
10113+ sql += querySource;
10114+
10115+ jrd_tra* traHandle = transaction;
10116+ const auto attachment = tdbb->getAttachment();
10117+
10118+ AutoSetRestoreFlag autoLttReferences(&dsqlScratch->flags,
10119+ DsqlCompilerScratch::FLAG_ALLOW_CREATED_LTT_REFERENCE, tempFlag == REL_temp_ltt);
10120+
10121+ // Clear TDBB_use_db_page_space so the INSERT uses per-transaction temp pages for GTT/LTT,
10122+ // not the structural base pages that were used during table creation.
10123+ AutoSetRestoreFlag<ULONG> noDbPageSpace(&tdbb->tdbb_flags, TDBB_use_db_page_space, false);
10124+
10125+ DSQL_execute_immediate(tdbb, attachment, &traHandle, sql.length(), sql.c_str(),
10126+ dsqlScratch->clientDialect, nullptr, nullptr, nullptr, nullptr, true);
10127+
10128+ fb_assert(traHandle == transaction);
10129+ }
10130+
993910131// Starting from the elements in a table definition, locate the PK columns if given in a
994010132// separate table constraint declaration.
994110133const ObjectsArray<MetaName>* CreateRelationNode::findPkColumns()
0 commit comments