void ModelExportHelper::exportToDBMS(DatabaseModel *db_model, Connection conn, const QString &pgsql_ver, bool ignore_dup, bool simulate) { int type_id; QString version, sql_buf, sql_cmd, lin; Connection new_db_conn; unsigned i, count; ObjectType types[]={OBJ_ROLE, OBJ_TABLESPACE}; BaseObject *object=nullptr; vector<Exception> errors; QTextStream ts; bool ddl_tk_found=false; /* Error codes treated in this method 42P04 duplicate_database 42723 duplicate_function 42P06 duplicate_schema 42P07 duplicate_table 42710 duplicate_object 42701 duplicate_column 42P16 invalid_table_definition Reference: http://www.postgresql.org/docs/current/static/errcodes-appendix.html*/ QString error_codes[]={"42P04", "42723", "42P06", "42P07", "42710", "42701", "42P16"}; vector<QString> err_codes_vect(error_codes, error_codes + sizeof(error_codes) / sizeof(QString)); try { if(!db_model) throw Exception(ERR_ASG_NOT_ALOC_OBJECT,__PRETTY_FUNCTION__,__FILE__,__LINE__); /* If the export is called using ignore duplications and simulation mode at same time an error is raised because the simulate mode (mainly used as SQL validation) cannot undo column addition (this can be changed in the future) */ if(simulate && ignore_dup) throw Exception(ERR_MIX_INCOMP_EXPORT_OPTS,__PRETTY_FUNCTION__,__FILE__,__LINE__); connect(db_model, SIGNAL(s_objectLoaded(int,QString,uint)), this, SLOT(updateProgress(int,QString,uint))); export_canceled=false; db_created=false; progress=sql_gen_progress=0; created_objs[OBJ_ROLE]=created_objs[OBJ_TABLESPACE]=-1; conn.connect(); //Retrive the DBMS version in order to generate the correct code version=(conn.getPgSQLVersion()).mid(0,3); //Overriding the DBMS version case the version is informed on parameter if(!pgsql_ver.isEmpty()) { SchemaParser::setPgSQLVersion(pgsql_ver); emit s_progressUpdated(progress, trUtf8("PostgreSQL version detection overrided. Using version %1...").arg(pgsql_ver)); } else { SchemaParser::setPgSQLVersion(version); emit s_progressUpdated(progress, trUtf8("PostgreSQL %1 server detected...").arg(version)); } if(ignore_dup) { emit s_progressUpdated(progress, trUtf8("Ignoring object duplication errors...")); //Save the current status for ALTER command generation for table columns/constraints saveGenAtlerCmdsStatus(db_model); } if(simulate) emit s_progressUpdated(progress, trUtf8("Simulation mode activated...")); //Creates the roles and tablespaces separately from the other objects for(type_id=0; type_id < 2 && !export_canceled; type_id++) { count=db_model->getObjectCount(types[type_id]); for(i=0; i < count && !export_canceled; i++) { object=db_model->getObject(i, types[type_id]); progress=((10 * (type_id+1)) + ((i/static_cast<float>(count)) * 10)); try { if(!object->isSQLDisabled()) { //Emits a signal indicating that the object is being exported emit s_progressUpdated(progress, trUtf8("Creating object `%1' (%2)...").arg(Utf8String::create(object->getName())).arg(object->getTypeName()), object->getObjectType()); sql_cmd=object->getCodeDefinition(SchemaParser::SQL_DEFINITION); conn.executeDDLCommand(sql_cmd); } } catch(Exception &e) { /* Raises an error if the object is duplicated and the ignore duplicity is not set or the error returned by the server is other than object duplicity */ if(!ignore_dup || (ignore_dup && std::find(err_codes_vect.begin(), err_codes_vect.end(), e.getExtraInfo())==err_codes_vect.end())) throw Exception(e.getErrorMessage(), e.getErrorType(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e, sql_cmd); else //If the object is duplicated store the error on a vector errors.push_back(e); } created_objs[types[type_id]]++; } } try { if(!db_model->isSQLDisabled() && !export_canceled) { //Creating the database on the DBMS emit s_progressUpdated(progress, trUtf8("Creating database `%1'...").arg(Utf8String::create(db_model->getName())), OBJ_DATABASE); sql_cmd=db_model->__getCodeDefinition(SchemaParser::SQL_DEFINITION); conn.executeDDLCommand(sql_cmd); db_created=true; } } catch(Exception &e) { /* Raises an error if the object is duplicated and the ignore duplicity is not set or the error returned by the server is other than object duplicity */ if(!ignore_dup || (ignore_dup && std::find(err_codes_vect.begin(), err_codes_vect.end(), e.getExtraInfo())==err_codes_vect.end())) throw Exception(e.getErrorMessage(), e.getErrorType(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e, sql_cmd); else errors.push_back(e); } if(!export_canceled) { //Connects to the new created database to create the other objects progress=20; new_db_conn=conn; new_db_conn.setConnectionParam(Connection::PARAM_DB_NAME, db_model->getName()); emit s_progressUpdated(progress, trUtf8("Connecting to database `%1'...").arg(Utf8String::create(db_model->getName()))); new_db_conn.connect(); progress=30; //Creating the other object types emit s_progressUpdated(progress, trUtf8("Creating objects on database `%1'...").arg(Utf8String::create(db_model->getName()))); //Generates the sql from entire model sql_buf=db_model->getCodeDefinition(SchemaParser::SQL_DEFINITION, false); /* Extract each SQL command from the buffer and execute them separately. This is done to permit the user, in case of error, identify what object is wrongly configured. */ ts.setString(&sql_buf); unsigned aux_prog=0, curr_size=0, buf_size=sql_buf.size(); progress+=(sql_gen_progress/progress); sql_cmd.clear(); while(!ts.atEnd() && !export_canceled) { try { //Cleanup single line comments lin=ts.readLine(); curr_size+=lin.size(); aux_prog=progress + ((curr_size/static_cast<float>(buf_size)) * 70); ddl_tk_found=(lin.indexOf(ParsersAttributes::DDL_END_TOKEN) >= 0); lin.remove(QRegExp("^(--)+(.)+$")); //If the line isn't empty after cleanup it will be included on sql command if(!lin.isEmpty()) sql_cmd += lin + "\n"; //If the ddl end token is found if(ddl_tk_found || (!sql_cmd.isEmpty() && ts.atEnd())) { //Regexp used to extract the object being created QRegExp reg=QRegExp("(CREATE)(.)+(\n)", Qt::CaseSensitive); sql_cmd.simplified(); //Check if the regex matches the sql command if(reg.exactMatch(sql_cmd)) { QString obj_type, obj_name; QRegExp reg_aux; unsigned obj_id; ObjectType obj_types[]={ OBJ_FUNCTION, OBJ_TRIGGER, OBJ_INDEX, OBJ_RULE, OBJ_TABLE, OBJ_VIEW, OBJ_DOMAIN, OBJ_SCHEMA, OBJ_AGGREGATE, OBJ_OPFAMILY, OBJ_OPCLASS, OBJ_OPERATOR, OBJ_SEQUENCE, OBJ_CONVERSION, OBJ_CAST, OBJ_LANGUAGE, OBJ_COLLATION, OBJ_EXTENSION, OBJ_TYPE }; unsigned count=sizeof(obj_types)/sizeof(ObjectType); int pos=0; //Get the fisrt line of the sql command, that contains the CREATE ... statement lin=sql_cmd.mid(0, sql_cmd.indexOf('\n')); for(obj_id=0; obj_id < count; obj_id++) { //Check if the keyword for the current object exists on string reg_aux.setPattern(QString("(CREATE)(.)*(%1)%2") .arg(BaseObject::getSQLName(obj_types[obj_id])) .arg(obj_types[obj_id]==OBJ_INDEX ? "( )*(CONCURRENTLY)?" : "")); pos=reg_aux.indexIn(lin); if(pos >= 0) { //Extracts from the line the string starting with the object's name lin=lin.mid(reg_aux.matchedLength(), sql_cmd.indexOf('\n')).simplified(); //Stores the object type name obj_type=BaseObject::getTypeName(obj_types[obj_id]); if(obj_types[obj_id]!=OBJ_CAST) { //The object name is the first element when splitting the string with space separator obj_name=lin.split(' ').at(0); obj_name.remove('('); } else { obj_name="cast" + lin.replace(" AS ",","); } obj_name.remove(';'); break; } } emit s_progressUpdated(aux_prog, trUtf8("Creating object `%1' (%2)...").arg(obj_name).arg(obj_type), obj_types[obj_id]); } else //General commands like alter / set aren't explicitly shown emit s_progressUpdated(aux_prog, trUtf8("Executing auxiliary command...")); //Executes the extracted SQL command if(!sql_cmd.isEmpty()) new_db_conn.executeDDLCommand(sql_cmd); sql_cmd.clear(); ddl_tk_found=false; } } catch(Exception &e) { if(ddl_tk_found) ddl_tk_found=false; if(!ignore_dup || (ignore_dup && std::find(err_codes_vect.begin(), err_codes_vect.end(), e.getExtraInfo())==err_codes_vect.end())) throw Exception(Exception::getErrorMessage(ERR_EXPORT_FAILURE).arg(Utf8String::create(sql_cmd)), ERR_EXPORT_FAILURE,__PRETTY_FUNCTION__,__FILE__,__LINE__,&e, sql_cmd); else { sql_cmd.clear(); errors.push_back(e); sleepThread(10); } } } } disconnect(db_model, nullptr, this, nullptr); if(ignore_dup) restoreGenAtlerCmdsStatus(); //Closes the new opened connection if(new_db_conn.isStablished()) new_db_conn.close(); /* If the process was a simulation or even canceled undo the export removing the created objects */ if(simulate || export_canceled) undoDBMSExport(db_model, conn); if(conn.isStablished()) conn.close(); if(!export_canceled) emit s_exportFinished(); else emit s_exportCanceled(); sleepThread(20); } catch(Exception &e) { disconnect(db_model, nullptr, this, nullptr); if(ignore_dup) restoreGenAtlerCmdsStatus(); try { //Closes the new opened connection if(new_db_conn.isStablished()) new_db_conn.close(); //Undo the export removing the created objects undoDBMSExport(db_model, conn); } catch(Exception &){} if(conn.isStablished()) conn.close(); /* When running in a separated thread (other than the main application thread) redirects the error in form of signal */ if(this->thread() && this->thread()!=qApp->thread()) { errors.push_back(e); emit s_exportAborted(Exception(e.getErrorMessage(), e.getErrorType(),__PRETTY_FUNCTION__,__FILE__,__LINE__, errors)); } else { //Redirects any error to the user if(errors.empty()) throw Exception(e.getErrorMessage(),e.getErrorType(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); else { errors.push_back(e); throw Exception(e.getErrorMessage(),__PRETTY_FUNCTION__,__FILE__,__LINE__, errors); } } } }
QString SafetVariable::createXMLFileFromQuery(const QSqlQuery& query, const QString& outputFileName ) const { QString result; Q_ASSERT_X(!outputFileName.isEmpty(), "SafetDocument::createXMLFileFromSQL()", qPrintable(QObject::tr("outputFileName vacio"))); if (outputFileName.isEmpty()){ qDebug("cadena outputFileName vacia"); return result; } QFile file; bool open; QTextStream out; bool istext = outputFileName.compare("::text", Qt::CaseInsensitive) == 0; if ( !istext ) { file.setFileName(outputFileName); open = file.open(QIODevice::WriteOnly | QIODevice::Text); Q_ASSERT_X(open, "SafetDocument::createXMLFileFromSQL()", qPrintable(QObject::tr("No se pudo crear el archivo XML correspondiente a la sentencia SQL."))); out.setDevice(&file); } else { out.setString(&result); } QSqlRecord rec; rec = query.record(); out << "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" << "\n"; out << "<libsafetdb>" << "\n"; QString cadena(""); //qDebug("<: %s", qPrintable(x.setNum(j+1)), ">"); // qDebug("\t<Document>"); out << "<Document>" << "\n" ; for (int i= 0; i< rec.count(); i++){ //qDebug(qPrintable(rec.fieldName(i))); //qDebug(qPrintable(query.value(i).toString())); cadena.append("<"); cadena.append(rec.fieldName(i)); cadena.append(">"); cadena.append(query.value(i).toString()); cadena.append("</"); cadena.append(rec.fieldName(i)); cadena.append(">"); // qDebug(qPrintable(cadena)); out << cadena << "\n" ; cadena.clear(); } // qDebug("</Document>"); out << "</Document>" << "\n" << "</libsafetdb>" << "\n"; return result; }