Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F193420
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
35 KB
Subscribers
None
View Options
diff --git a/src/updater.cpp b/src/updater.cpp
--- a/src/updater.cpp
+++ b/src/updater.cpp
@@ -1,885 +1,885 @@
#include "updater.h"
#include "psettings.h"
#include <ksettings.h>
#include <sqlproc.h>
#include <libpq-fe.h>
#include <QDate>
#include <QDir>
#include <QTextCodec>
#include <QXmlStreamReader>
DatabaseUpdater::DatabaseUpdater()
: QObject()
, _pset(0)
, _revisionBefore(0)
, _revisionAfter(0)
{
}
DatabaseUpdater::~DatabaseUpdater()
{
delete _pset;
}
int DatabaseUpdater::run( ProgramSettings& a_pset )
{
_pset = new ProgramSettings( a_pset );
if ( !checkArguments() )
return -1;
if ( !readConfig() )
return -1;
if ( !loadScriptsFromResource() )
return -1;
if ( !runScripts() )
return -1;
return 0;
}
//---------------------------------------------------------------------------
bool DatabaseUpdater::checkArguments()
{
if ( _pset->controlFile.isEmpty() )
{
emit error( QString::fromUtf8( "Не задан файл конфигурации." ) );
return false;
}
//если не задано полное имя файла конфигурации, то искать его в текущем каталоге
QString filename = _pset->controlFile;
if ( !QDir::isAbsolutePath( filename ) )
filename = QString( "%1/%2" ).arg( QDir::currentPath() ).arg( _pset->controlFile );
//проверить наличие файла
if ( !QFile::exists( filename ) )
{
emit error( QString::fromUtf8( "Не найден файл конфигурации\n" ) +
QDir::toNativeSeparators( filename ) );
return false;
}
_pset->controlFile = filename;
return true;
}
//---------------------------------------------------------------------------
bool DatabaseUpdater::readConfig()
{
//открываем входной файл
QFile controlFile( _pset->controlFile );
if ( !controlFile.open( QIODevice::ReadOnly ) )
{
emit error( QString::fromUtf8( "Сбой при загрузке файла конфигурации:\n"
"Невозможно открыть для чтения файл %1" ).arg( QDir::toNativeSeparators(
_pset->controlFile ) ) );
return false;
}
//парсим входной файл
QXmlStreamReader xml;
xml.setDevice( &controlFile );
emit message( QString::fromUtf8( "Загрузка конфигурации из файла\n%1" ).
arg( QDir::toNativeSeparators( _pset->controlFile ) ) );
//идём по элементам документа
while ( !xml.atEnd() )
{
xml.readNext();
if ( xml.isStartElement() && xml.name() == "package" )
if ( !readPackage( xml ) )
return false;
}
if ( xml.hasError() )
{
emit error( QString::fromUtf8( "Сбой при загрузке файла конфигурации:\n"
"Ошибка: %1, строка %2, позиция %3").
arg( xml.errorString() ).arg( xml.lineNumber() ).arg( xml.columnNumber() ) );
return false;
}
controlFile.close();
//найти файл с расширением pkginfo и именем как у входного файла, если такого нет,
//то использовать первый попавшийся файл с расширением pkginfo;
//прочитать из него идентификатор пакета и имя базы данных;
//если файла нет, то и не надо
QFileInfo fi( controlFile );
QStringList files = QDir( QFileInfo( controlFile ).path(), "*.pkginfo",
QDir::NoSort, QDir::Files ).entryList();
if ( !files.isEmpty() )
{
QString pkgfile = QFileInfo( controlFile ).completeBaseName() + ".pkginfo";
if ( !files.contains( pkgfile, Qt::CaseInsensitive ) )
pkgfile = files.at( 0 );
pkgfile = QFileInfo( controlFile ).path() + '/' + pkgfile;
emit message( QString::fromUtf8( "Загрузка конфигурации из файла\n%1" ).
arg( QDir::toNativeSeparators( pkgfile ) ) );
KSettings pkginfo( pkgfile );
pkginfo.beginGroup( "package" );
QString s = pkginfo.value( "dbname" ).toString();
if ( !s.isEmpty() && _pset->database.isEmpty() )
_pset->database = s;
QStringList ver = pkginfo.value( "version" ).toString().split( QChar('.') );
if ( ver.size() > 1 )
{
s = ver.at( 1 );
bool ok;
int i = s.toInt( &ok );
if ( ok )
_pset->dbVersion = i;
}
_pset->packageId = pkginfo.value( "id" ).toString();
}
//после загрузки конфигурации из файлов должно быть определено имя БД
if ( _pset->database.isEmpty() )
{
emit error( QString::fromUtf8( "Не задано имя базы данных" ) );
return false;
}
return true;
}
//---------------------------------------------------------------------------
bool DatabaseUpdater::readPackage( QXmlStreamReader& a_xml )
{
const QXmlStreamAttributes& packageAttrs = a_xml.attributes();
QString packageId = packageAttrs.value( "id" ).toString();
QString uriAttr = packageAttrs.value( "uri" ).toString();
bool uri = !((uriAttr == "no") || (uriAttr == "нет"));
Package* package = new Package( packageId, uri );
_packages.append( package );
//собираем информацию о скриптах данного пакета
const QString SCRIPT_NODE( "script" );
const QString REVISION_ATTR( "revision" );
const QString TRANSACTION_ATTR( "transaction" );
const QString COMMENT_ATTR( "comment" );
const QString SCRIPT_ATTR( "file" );
const QString URI_DATA_ATTR( "udata" );
const QString NO_REQUIRED_ATTR = QString::fromUtf8( "Неправильное содержание файла конфигурации:\n"
"Не указан обязательный атрибут «%1» пакета «%2»" );
while ( !a_xml.atEnd() )
{
a_xml.readNext();
if ( a_xml.isStartElement() && a_xml.name() == SCRIPT_NODE )
{
const QXmlStreamAttributes& attrs = a_xml.attributes();
//проверка наличия обязательных атрибутов
if ( !attrs.hasAttribute( REVISION_ATTR ) )
{
emit error( NO_REQUIRED_ATTR.arg( REVISION_ATTR ).arg( packageId ) );
return false;
}
if ( !attrs.hasAttribute( SCRIPT_ATTR ) )
{
emit error( NO_REQUIRED_ATTR.arg( SCRIPT_ATTR ).arg( packageId ) );
return false;
}
//проверка правильности указания атрибутов
bool ok;
int revision = attrs.value( REVISION_ATTR ).toString().toInt( &ok );
if ( !ok )
{
emit error( QString::fromUtf8(
"Атрибут «revision» пакета «%1» должен быть числом" ).
arg( packageId ) );
return false;
}
//заносим информацию о скрипте в список скриптов пакета
QString file = attrs.value( SCRIPT_ATTR ).toString();
QString uriScript = attrs.value( URI_DATA_ATTR ).toString();
QString comment = attrs.value( COMMENT_ATTR ).toString();
QString strans = attrs.value( TRANSACTION_ATTR ).toString();
bool transaction = !((strans == "0") ||
(strans.compare( "no", Qt::CaseInsensitive ) == 0) ||
(strans.compare( "нет", Qt::CaseInsensitive ) == 0));
DatabaseScript* script = new DatabaseScript( revision, transaction,
file, uriScript, comment );
package->addScript( script );
}
}
//упорядочить скрипты по возрастанию номеров ревизий
package->sortScripts();
return true;
}
//---------------------------------------------------------------------------
bool DatabaseUpdater::runScripts()
{
//определение пакета, скрипты которого будут выполняться
Package* package = 0;
QListIterator<Package*> it( _packages );
while ( it.hasNext() )
{
package = it.next();
if ( package->id() == _pset->packageId )
break;
else
package = 0;
}
if ( !package )
{
emit error( QString::fromUtf8( "Для пакета «%1» не задано ни одного "
"сценария создания базы данных" ).arg( _pset->packageId ) );
return false;
}
//проверка наличия файлов со скриптами на диске
QStringList paths;
QFileInfo fi( _pset->controlFile );
paths << fi.canonicalPath() << fi.canonicalPath() + "/script" << QDir::currentPath();
DatabaseScript* script = 0;
QListIterator<DatabaseScript*> it2( package->scripts() );
while ( it2.hasNext() )
{
script = it2.next();
if ( !script->findScript( paths ) )
{
emit error( QString::fromUtf8( "Не найден файл сценария создания "
"базы данных %1" ).arg( script->script() ) );
return false;
}
if ( package->uri() && !script->findUriScript( paths ) )
{
emit error( QString::fromUtf8( "Не найден файл условно-реальной "
"информации %1" ).arg( script->uriScript() ) );
return false;
}
}
QString curDate = QDate::currentDate().toString( Qt::ISODate );
SqlProcessor proc;
SqlProcessor uriProc;
emit message( QString::fromUtf8( "Подключение к серверу баз данных" ) );
//пока идут служебные подключения к БД и запросы, подключаем только сигнал error
connect( &proc, SIGNAL(error(const QString&,const QString&,const QString&)),
this, SIGNAL(sqlError(const QString&,const QString&,const QString&)) );
connect( &uriProc, SIGNAL(error(const QString&,const QString&,const QString&)),
this, SIGNAL(sqlError(const QString&,const QString&,const QString&)) );
//---- template1 ----
//попытка подключения к template1 и получение списка таблиц
if ( !proc.connectdb( _pset->host, _pset->port, "template1", _pset->username,
_pset->password ) )
return false;
QStringList template1Tables = databaseTableList( proc );
int currentDatabaseRevision = 0; //БД нет или пустая
//удаление БД если задано параметром при запуске программы
bool dbExists = databaseExists( proc, _pset->database );
if ( dbExists && _pset->dropdb )
{
emit message( QString::fromUtf8( "Удаление базы данных <b>%1</b>" ).arg( _pset->database ) );
if ( !dropDatabase( proc, _pset ) )
return false;
dbExists = false;
}
//создание БД если она не существует
if ( !dbExists )
{
emit message( QString::fromUtf8( "Создание базы данных <b>%1</b>" ).arg( _pset->database ) );
if ( !createDatabase( proc, _pset ) )
return false;
}
QString uriDatabase = _pset->database + "_u";
if ( package->uri() )
{
//удаление учебной БД если задано параметром при запуске программы
bool uriDbExists = databaseExists( proc, uriDatabase );
if ( uriDbExists && _pset->dropdb )
{
emit message( QString::fromUtf8( "Удаление учебной базы данных <b>%1</b>" ).arg( uriDatabase ) );
if ( !dropDatabase( proc, _pset, uriDatabase ) )
return false;
uriDbExists = false;
}
//создание учебной БД если она не существует
if ( !uriDbExists )
{
emit message( QString::fromUtf8( "Создание учебной базы данных <b>%1</b>" ).arg( uriDatabase ) );
if ( !createDatabase( proc, _pset, uriDatabase ) )
return false;
}
}
connect( &proc, SIGNAL(afterConnect(QString,QString,QString,QString,QString)),
this, SLOT(afterConnect(QString,QString,QString,QString,QString)) );
//---- database ----
//подключение к созданной/существующей БД и получение списка таблиц
if ( !proc.connectdb( _pset->host, _pset->port, _pset->database, _pset->username,
_pset->password ) )
return false;
QStringList databaseTables = databaseTableList( proc );
//подключение к учебной БД и получение списка таблиц
QStringList uriDatabaseTables;
if ( package->uri() )
{
//---- database_u ----
if ( !uriProc.connectdb( _pset->host, _pset->port, uriDatabase,
_pset->username, _pset->password ) )
return false;
uriDatabaseTables = databaseTableList( uriProc );
}
//считывание данных о версии БД из таблицы dm_version,
//эта таблица существует только в основной БД, версия учебной должна совпадать
bool legacyDatabase = false;
proc.execSQL( "select relnatts from pg_class "
"where relname='dm_version' and relkind='r'" );
PGresult* pgresult = proc.result().pgresult;
//если пустой результат запроса, значит таблицы dm_version нет в БД
// bool createDmVersion = data.size() == 0;
bool createDmVersion = PQntuples(pgresult) == 0;
//если таблица есть, то сравнить число её атрибутов с эталоном
if (!createDmVersion)
{
const char* pgvalue = PQgetvalue(pgresult, 0, 0);
if ( QByteArray::fromRawData(pgvalue, qstrlen(pgvalue)).toInt() != DM_VERSION_FIELDS_COUNT )
{ //не та структура, удаляем таблицу
if ( !proc.execSQL( "drop table dm_version" ) )
return false;
createDmVersion = true;
}
}
if ( createDmVersion )
{ //БД уже существовала, а таблицы dm_version в ней нет, или не та структура
if ( databaseTables != template1Tables )
{
legacyDatabase = true;
currentDatabaseRevision = 1;
}
emit message( QString::fromUtf8( "Создание таблицы изменений БД" ) );
proc.execSQL( "begin" );
if ( !proc.execute( _createDmVersionScript ) )
{
emit error( QString::fromUtf8( "Сбой при создании таблицы изменений БД" ) );
return false;
}
if ( legacyDatabase )
{ //запись информации о версии №1 в unversioned БД
if ( !proc.execSQL( QString::fromUtf8( "insert into dm_version "
"(revision,package_id,comment,gen_date) values "
"(1,'%1','Изначальная версия','%2')" ).arg(
package->id(), curDate ) ) )
return false;
}
proc.execSQL( "commit" );
}
else
{
proc.execSQL( QString("select max(revision), count(*) from dm_version "
"where package_id='%1'" ).arg( package->id() ) );
PGresult* pgresult = proc.result().pgresult;
if (PQntuples(pgresult))
{
const char* pgvalue = PQgetvalue(pgresult, 0, 1);
if (QByteArray::fromRawData(pgvalue, qstrlen(pgvalue)).toInt() > 0)
{
pgvalue = PQgetvalue(pgresult, 0, 0);
currentDatabaseRevision = QByteArray::fromRawData(pgvalue, qstrlen(pgvalue)).toInt();
}
}
}
//создание языка plpgsql
if ( !createLanguagePlpgsql( proc, uriProc, package->uri() ) )
return false;
_revisionAfter = _revisionBefore = currentDatabaseRevision;
//выполнение необходимых скриптов
connect( &proc, SIGNAL(progress(int)), this, SIGNAL(progress(int)) );
connect( &uriProc, SIGNAL(progress(int)), this, SIGNAL(progress(int)) );
QListIterator<DatabaseScript*> iter( package->scripts() );
while ( iter.hasNext() )
{
script = iter.next();
int revision = script->revision();
bool transaction = script->transaction();
//если была найдена изначальная БД, то всё уже сделано для 1-й версии
if ( (revision == 1) && legacyDatabase )
continue;
//пропускаем уже установленные версии БД
if ( revision <= currentDatabaseRevision )
continue;
if ( revision == 1 )
emit message( QString::fromUtf8( "Создание базы данных версии %1" ).arg( revision ) );
else
emit message( QString::fromUtf8( "Обновление базы данных до версии %1" ).arg( revision ) );
//подготовка скрипта к выполнению
QList<QByteArray> mainScript;
QList<QByteArray> globalsScript;
prepareScripts( script->script(), mainScript, globalsScript );
//если в скрипте были команды создания глобальных объектов, то выполнить
//их в отдельной транзакции
if ( globalsScript.size() > 0 )
{
proc.execSQL( "begin" );
if ( !proc.execute( globalsScript ) )
return false;
proc.execSQL( "commit" );
}
//выполнение скрипта
if ( transaction )
proc.execSQL( "begin" );
if ( !proc.execute( mainScript ) )
return false;
//выполнение скриптов в учебной БД, если задано её создание
if ( package->uri() )
{
if ( transaction )
uriProc.execSQL( "begin" );
if ( revision == 1 )
emit message( QString::fromUtf8( "Создание учебной базы данных версии %1" ).arg( revision ) );
else
emit message( QString::fromUtf8( "Обновление учебной базы данных до версии %1" ).arg( revision ) );
if ( !uriProc.execute( mainScript ) )
{
if ( transaction )
proc.execSQL( "rollback" );
return false;
}
if ( !script->uriScript().isEmpty() )
{
emit message( QString::fromUtf8( "Загрузка условной информации в учебную базу данных" ) );
if ( !uriProc.execute( script->uriScript() ) )
{
if ( transaction )
proc.execSQL( "rollback" );
return false;
}
}
if ( !uriProc.execute( _setSearchPathScript ) )
return false;
clearMaclabels( uriProc );
if ( transaction )
uriProc.execSQL( "commit" );
}
//сброс параметра search_path, он мог быть изменён при выполнении скрипта
if ( !proc.execute( _setSearchPathScript ) )
return false;
//запись информации о версии в БД
if ( !proc.execSQL( QString::fromUtf8( "insert into dm_version "
"(revision,package_id,comment,gen_date) values "
"(%1,'%2','%3','%4')" ).arg( revision ).
arg( package->id() ).arg( script->comment() ).
arg( curDate ) ) )
return false;
//сброс мандатных меток, если они есть в БД
clearMaclabels( proc );
if ( transaction )
proc.execSQL( "commit" );
_revisionAfter = revision;
}
return true;
}
//---------------------------------------------------------------------------
bool DatabaseUpdater::databaseExists( SqlProcessor& a_proc, const QString& a_dbname )
{
a_proc.execSQL( QString( "select 1 from pg_database where datname='%1\'" ).arg(a_dbname) );
return PQntuples(a_proc.result().pgresult) == 1;
}
//---------------------------------------------------------------------------
bool DatabaseUpdater::createDatabase( SqlProcessor& a_proc, ProgramSettings* a_pset,
const QString& a_dbname )
{
if ( a_dbname.isEmpty() && a_pset->database.isEmpty() )
return false;
QString dbname = (a_dbname.isEmpty() ? a_pset->database : a_dbname );
//если уже подключены к указанной БД, то отключение
if ( a_proc.database() == dbname )
a_proc.disconnectdb();
//если не подключены, то подключение к template1
if ( a_proc.database().isNull() )
{
if ( !a_proc.connectdb( a_pset->host, a_pset->port, QString( "template1" ),
a_pset->username, a_pset->password ) )
return false;
}
//если БД уже существует, то создавать не надо
if ( databaseExists( a_proc, dbname ) )
return true;
return a_proc.execSQL( QString( "create database \"%1\"" ).arg(dbname) )
&& a_proc.commandStatus() == QString( "CREATE DATABASE" );
}
//---------------------------------------------------------------------------
bool DatabaseUpdater::dropDatabase( SqlProcessor& a_proc, ProgramSettings* a_pset,
const QString& a_dbname )
{
if ( a_pset->database.isEmpty() )
return false;
QString dbname = (a_dbname.isEmpty() ? a_pset->database : a_dbname );
//если уже подключены к указанной БД, то отключение
if ( a_proc.database() == dbname )
a_proc.disconnectdb();
//если не подключены, то подключение к template1
if ( a_proc.database().isNull() )
{
if ( !a_proc.connectdb( a_pset->host, a_pset->port, QString( "template1" ),
a_pset->username, a_pset->password ) )
return false;
}
//если БД не существует, то удалять не надо
if ( !databaseExists( a_proc, dbname ) )
return true;
return a_proc.execSQL( QString( "drop database \"%1\"" ).arg(dbname) )
&& a_proc.commandStatus() == QString( "DROP DATABASE" );
}
//---------------------------------------------------------------------------
// Получение списка таблиц в БД
//---------------------------------------------------------------------------
QStringList DatabaseUpdater::databaseTableList(SqlProcessor& a_proc)
{
QStringList result;
if (!a_proc.execSQL("select tablename from pg_tables order by tablename"))
return result;
SqlResult sqlresult = a_proc.result();
PGresult* pgresult = sqlresult.pgresult;
QTextCodec* codec = sqlresult.codec;
int numTuples = PQntuples(pgresult);
for (int i = 0; i < numTuples; ++i)
{
if (PQgetisnull(pgresult, i, 0))
result.append(QString());
else
result.append(codec->toUnicode(PQgetvalue(pgresult, i, 0)));
}
return result;
}
//---------------------------------------------------------------------------
bool DatabaseUpdater::loadScriptsFromResource()
{
QString errmess = QString::fromUtf8( "Сбой при чтении ресурсов программы" );
SqlProcessor proc;
QFile resFile( ":/dm_version.sql" );
if ( !(resFile.open( QIODevice::ReadOnly ) ) )
{
emit error( errmess );
return false;
}
_createDmVersionScript = proc.parse( resFile );
resFile.close();
resFile.setFileName( ":/create_helper_functions.sql");
if ( !(resFile.open( QIODevice::ReadOnly ) ) )
{
emit error( errmess );
return false;
}
_createHelperFunctionsScript = proc.parse( resFile );
resFile.close();
resFile.setFileName( ":/drop_helper_functions.sql");
if ( !(resFile.open( QIODevice::ReadOnly ) ) )
{
emit error( errmess );
return false;
}
_dropHelperFunctionsScript = proc.parse( resFile );
resFile.close();
resFile.setFileName( ":/set_search_path.sql");
if ( !(resFile.open( QIODevice::ReadOnly ) ) )
{
emit error( errmess );
return false;
}
_setSearchPathScript = proc.parse( resFile );
return true;
}
//---------------------------------------------------------------------------
// Подготавливает скрипт, считанный из файла, к выполнению в БД.
// Команды анализируются и разделяются на два скрипта — основной и глобальных
// объектов. Обработка заключается в следующем:
// 1. Команды создания глобальных объектов
// CREATE GROUP
// CREATE USER
// CREATE ROLE
// CREATE TABLESPACE
// заменяются вызовами функций-обёрток для их безопасного выполнения.
// Эти вызовы вставляются в скрипт глобальных объектов. В этот же скрипт
// добавляются команды создания функций-обёрток и их удаления.
// 2. Команды установки кодировки клиента
// SET CLIENT_ENCODING
// SET NAMES
// \encoding
// добавляются в оба скрипта.
// 3. Команда подключения языка plpgsql
// CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE plpgsql
// игнорируется и не попадает ни в один скрипт. Создание языка plpgsql
// производится отдельно, перед началом выполнения скриптов.
//---------------------------------------------------------------------------
void DatabaseUpdater::prepareScripts( const QString& a_filename,
QList<QByteArray>& oa_mainScript,
QList<QByteArray>& oa_globalsScript )
{
//пропустим файл через парсер, на выходе список команд
bool helperInjected = false;
SqlProcessor proc;
QList<QByteArray> result = proc.parse( a_filename );
//обход списка и анализ команд
QListIterator<QByteArray> it( result );
while ( it.hasNext() )
{
const QByteArray line = it.next();
int i = 0;
int end = line.size();
//пропускаем первое слово, перед ним пробелов нет, парсер их убирает
while ( i != end && !QChar(line.at( i )).isSpace() )
++i;
//анализируем первое слово
QByteArray command1 = line.left( i ).toLower();
if ( command1 == "\\encoding" )
{
oa_mainScript.append( line );
oa_globalsScript.append( line );
continue;
}
//переход на начало второго слова
while ( i != end && QChar(line.at( i )).isSpace() )
++i;
int p = i;
//пропускаем второе слово
while ( i != end && !QChar(line.at( i )).isSpace() )
++i;
//анализируем команду
QByteArray command2 = line.mid( p, i - p ).toLower();
if ( command1 == "set" )
{
- oa_mainScript.append( originalLine );
- if ( command2 == "names" || command2 == "client_encoding" )
- oa_globalsScript.append( originalLine );
+ oa_mainScript.append( line );
+ if ( command2 == "names" || command2.startsWith( "client_encoding" ) )
+ oa_globalsScript.append( line );
}
else if ( command1 == "create" )
{
if ( command2 == "group" || command2 == "user" ||
command2 == "role" || command2 == "tablespace" )
{ //добавляем в выходной скрипт globals вызов безопасной функции-обёртки
if (!helperInjected)
{ //но сначала вставляем команды создания функций-обёрток
helperInjected = true;
QListIterator<QByteArray> helperIter(_createHelperFunctionsScript);
while (helperIter.hasNext())
oa_globalsScript.append(helperIter.next());
}
//переход на начало имени объекта
while ( i != end && QChar(line.at( i )).isSpace() )
++i;
QByteArray name;
if ( i != end )
{
if ( line.at( i ) == '"' )
{ //если имя объекта начинается с двойной кавычки, то пропуск до следующей
//двойной кавычки
++i; //пропустить открывающую двойную кавычку
p = i;
while ( i != end && line.at( i ) != '"' )
++i;
name = line.mid( p, i - p );
if ( i != end )
++i; //пропустить закрывающую двойную кавычку
}
else
{ //пропуск до конца слова
p = i;
while ( i != end && !QChar(line.at( i )).isSpace() )
++i;
name = line.mid( p, i - p );
if ( name.size() > 0 && name.at( name.size() - 1 ) == ';' )
name.chop( 1 );
}
}
QByteArray parameters( line.right( end - i ) );
if ( parameters.size() > 0 && parameters.at( parameters.size() - 1 ) == ';' )
parameters.chop( 1 );
QByteArray safeCall( "select _rct_safe_create_" );
safeCall.append( command2 ).append( "('" ).append( name ).append( "','" )
.append( parameters ).append( "');" );
oa_globalsScript.append( safeCall );
}
else if ( command2 == "trusted" || command2 == "procedural" ||
command2 == "language" )
{ //create language не нужен
continue;
}
else
{ //create неглобального объекта, в основной скрипт
oa_mainScript.append( line );
}
}
else
{ //все остальные команды в основной скрипт
oa_mainScript.append( line );
}
} //цикл по командам
if ( helperInjected )
oa_globalsScript.append( _dropHelperFunctionsScript );
}
//---------------------------------------------------------------------------
void DatabaseUpdater::clearMaclabels( SqlProcessor& a_proc )
{
a_proc.execSQL( "select distinct 1 from pg_attribute a join pg_class c "
"on (a.attrelid=c.oid) where c.relname='pg_class' and a.attname='relmaclabel'" );
if ( PQntuples(a_proc.result().pgresult) == 1 )
a_proc.execSQL( "update pg_class set relmaclabel=null" );
}
//---------------------------------------------------------------------------
bool DatabaseUpdater::createLanguagePlpgsql( SqlProcessor& a_proc,
SqlProcessor& a_uriProc,
bool a_uri )
{
static const char* CREATE_SQL = "create language plpgsql";
static const char* CHECK_SQL = "select 1 from pg_language where lanname='plpgsql'";
a_proc.execSQL( CHECK_SQL );
if ( PQntuples(a_proc.result().pgresult) == 0 )
{
if ( !a_proc.execSQL( CREATE_SQL ) )
return false;
}
if ( a_uri )
{
a_uriProc.execSQL( CHECK_SQL );
if ( PQntuples(a_uriProc.result().pgresult) == 0 )
{
if ( !a_uriProc.execSQL( CREATE_SQL ) )
return false;
}
}
return true;
}
//---------------------------------------------------------------------------
void DatabaseUpdater::afterConnect( const QString& a_host, const QString& a_port,
const QString& a_database, const QString& a_username,
const QString& a_password )
{
Q_UNUSED(a_port);
Q_UNUSED(a_password);
emit logConnectionParameters( a_host, a_database, a_username );
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
bool DatabaseScript::findScript( const QStringList& a_paths )
{
_script.replace( QChar('\\'), QChar('/') );
foreach( QString path, a_paths )
{
QDir dir( path );
if ( dir.exists( _script ) )
{
_script = dir.absoluteFilePath( _script );
return true;
}
}
return false;
}
//---------------------------------------------------------------------------
bool DatabaseScript::findUriScript( const QStringList& a_paths )
{
_uriScript.replace( QChar('\\'), QChar('/') );
if ( _uriScript.isEmpty() )
return true;
foreach( QString path, a_paths )
{
QDir dir( path );
if ( dir.exists( _uriScript ) )
{
_uriScript = dir.absoluteFilePath( _uriScript );
return true;
}
}
return false;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Wed, Jun 11, 8:14 PM (1 d, 16 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
127137
Attached To
rRCT Программа создания/обновления структуры БД
Event Timeline
Log In to Comment