Skip to content

Commit

Permalink
Allow use of prepared SQL statements in {{#get_db_data:}}
Browse files Browse the repository at this point in the history
Allow use of prepared SQL statements in {{#get_db_data:}}
for ODBC connections and mySQL.

Define prepared SQL statements in LocalSettings.php per database
connection.

Examples:

    One statement per connection:

In LocalSettings.php:

$edgDBServer    ['rfam']        = 'mysql-rfam-public.ebi.ac.uk:4497';
$edgDBServerType['rfam']        = 'mysql';
$edgDBName      ['rfam']        = 'Rfam';
$edgDBUser      ['rfam']        = 'rfamro';
$edgDBPass      ['rfam']        = '';
$edgDBPrepared  ['rfam']        = <<<'SQL'
SELECT fr.rfam_acc, fr.rfamseq_acc, fr.seq_start, fr.seq_end
FROM full_region fr, rfamseq rf, taxonomy tx
WHERE rf.ncbi_id = tx.ncbi_id
AND fr.rfamseq_acc = rf.rfamseq_acc
AND tx.ncbi_id = ?
AND is_significant = 1 -- exclude low-scoring matches from the same clan
SQL;
$edgDBTypes     ['rfam']        = 's'; // optional.

In wikitext:

{{#get_db_data:
db = rfam
| parameters=10116 <!-- substitutes ?'s in prepared statement -->
| data=account=rfam_acc,sec=rfamseq_acc,start=seq_start,end=seq_end
}}

    Several statements per connection:

In LocalSettings.php:

$edgDBServer    ['rfam']        = 'mysql-rfam-public.ebi.ac.uk:4497';
$edgDBServerType['rfam']        = 'mysql';
$edgDBName      ['rfam']        = 'Rfam';
$edgDBUser      ['rfam']        = 'rfamro';
$edgDBPass      ['rfam']        = '';
$edgDBPrepared  ['rfam']        = [
        'sequences' => <<<'SEQ'
SELECT fr.rfam_acc, fr.rfamseq_acc, fr.seq_start, fr.seq_end
FROM full_region fr, rfamseq rf, taxonomy tx
WHERE rf.ncbi_id = tx.ncbi_id
AND fr.rfamseq_acc = rf.rfamseq_acc
AND tx.ncbi_id = ?
AND is_significant = 1 -- exclude low-scoring matches from the same clan
SEQ,
        'sno' => <<<'SNO'
SELECT fr.rfam_acc, fr.rfamseq_acc, fr.seq_start, fr.seq_end, f.type
FROM full_region fr, rfamseq rf, taxonomy tx, family f
WHERE
rf.ncbi_id = tx.ncbi_id
AND f.rfam_acc = fr.rfam_acc
AND fr.rfamseq_acc = rf.rfamseq_acc
AND tx.tax_string LIKE ?
AND f.type LIKE '%snoRNA%'
AND is_significant = 1 -- exclude low-scoring matches from the same clan
SNO];

In wikitext:

{{#get_db_data:
db = rfam
| query=sequences <!-- which prepared statement? -->
| parameters=10116 <!-- substitutes ?'s in prepared statement -->
| data=account=rfam_acc,sec=rfamseq_acc,start=seq_start,end=seq_end
}}

If prepared SQL statements are defined for a database connection,
arbitrary SQL queries are effectively disallowed.

Changes to the class hierarchy:
* EDConnectorBase
...
** EDConnectorDb
...
*** EDConnectorComposed (new, abstract)
**** EDConnectorRelational (abstract)
***** EDConnectorRdbms (new, for DBs handled by Wikimedia\Rdbms\Database)
...
**** EDConnectorMongoDb
...
*** EDConnectorPrepared (new, abstract)
**** EDConnectorPreparedMysql (new)

The new classes EDConnectorComposed and EDConnectorPrepared are contraposed.

In addition, some property names are brought to camelCase, some methods
are renamed and some unnecessary contructors are removed;
the class ParsesParams now handles warning suppression.

Bug: T287328
Change-Id: Ibf7593eff63074bda86cdaf3b0a6e7a2fc2708bd
  • Loading branch information
alex-mashin committed Aug 25, 2021
1 parent 13497b7 commit d17b824
Show file tree
Hide file tree
Showing 41 changed files with 826 additions and 573 deletions.
2 changes: 2 additions & 0 deletions .phpcs.xml
Expand Up @@ -10,6 +10,8 @@
</property>
</properties> -->
<exclude name="MediaWiki.WhiteSpace.SpaceBeforeSingleLineComment.NewLineComment" />
<!-- I want to use assignments in while loops. -->
<exclude name="MediaWiki.ControlStructures.AssignmentInControlStructures.AssignmentInControlStructures" />
</rule>
<!-- RedundantVarName is currently too sensitive, incompatible with default Doxygen. -->
<rule ref="MediaWiki.Commenting.RedundantVarName.Found">
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Expand Up @@ -6,7 +6,8 @@
"symfony/css-selector": "~5.1"
},
"require-dev": {
"mediawiki/mediawiki-codesniffer": "37.0.0",
"roave/security-advisories": "dev-latest",
"mediawiki/mediawiki-codesniffer": "36.0.0",
"mediawiki/minus-x": "1.1.1",
"php-parallel-lint/php-console-highlighter": "0.5.0",
"php-parallel-lint/php-parallel-lint": "1.3.0"
Expand Down
35 changes: 13 additions & 22 deletions extension.json
Expand Up @@ -46,12 +46,16 @@
"EDConnectorFile": "includes/connectors/EDConnectorFile.php",
"EDConnectorDirectory": "includes/connectors/EDConnectorDirectory.php",
"EDConnectorDb": "includes/connectors/EDConnectorDb.php",
"EDConnectorComposed": "includes/connectors/EDConnectorComposed.php",
"EDConnectorRelational": "includes/connectors/EDConnectorRelational.php",
"EDConnectorRdbms": "includes/connectors/EDConnectorRdbms.php",
"EDConnectorSql": "includes/connectors/EDConnectorSql.php",
"EDConnectorSqlite": "includes/connectors/EDConnectorSqlite.php",
"EDConnectorMongodb": "includes/connectors/EDConnectorMongodb.php",
"EDConnectorMongodb5": "includes/connectors/EDConnectorMongodb5.php",
"EDConnectorMongodb7": "includes/connectors/EDConnectorMongodb7.php",
"EDConnectorPrepared": "includes/connectors/EDConnectorPrepared.php",
"EDConnectorPreparedMysql": "includes/connectors/EDConnectorPreparedMysql.php",
"EDParserBase": "includes/parsers/EDParserBase.php",
"EDParserText": "includes/parsers/EDParserText.php",
"EDParserRegex": "includes/parsers/EDParserRegex.php",
Expand All @@ -71,34 +75,20 @@
},
"config": {
"_prefix": "edg",
"Values": [],
"ExternalValueVerbose": true,
"StringReplacements": [],
"CacheTable": null,
"AlwaysAllowStaleCache": true,
"CacheTable": null, "AlwaysAllowStaleCache": true, "CacheExpireTime": 604800,
"AllowSSL": true,
"ExternalValueVerbose": true,
"CacheExpireTime": 604800,
"TryEncodings": [ "ASCII", "UTF-8", "Windows-1251", "Windows-1252", "Windows-1254", "KOI8-R", "ISO-8859-1" ],
"DBServer": [],
"DBServerType ": [],
"DBName": [],
"DBUser": [],
"DBPass": [],
"DBDirectory": [],
"DBFlags": [],
"DBTablePrefix": [],
"DirectoryPath": [],
"FilePath": [],
"LDAPServer": [],
"LDAPUser": [],
"LDAPPass": [],
"LDAPBaseDN": [],
"HTTPOptions": {
"timeout": "default"
},
"TryEncodings": [ "ASCII", "UTF-8", "Windows-1251", "Windows-1252", "Windows-1254", "KOI8-R", "ISO-8859-1" ],
"DBServer": [], "DBServerType ": [], "DBName": [], "DBUser": [], "DBPass": [], "DBDirectory": [], "DBFlags": [], "DBTablePrefix": [], "DBPrepared": [], "DBTypes": [],
"DirectoryPath": [], "FilePath": [],
"LDAPServer": [], "LDAPUser": [], "LDAPPass": [], "LDAPBaseDN": [],
"Secrets": {
"server": [ "DBServer", "DBServerType", "DBName", "DBUser", "DBPass", "DBDirectory", "DBFlags", "DBTablePrefix" ],
"db": [ "DBServer", "DBServerType", "DBName", "DBUser", "DBPass", "DBDirectory", "DBFlags", "DBTablePrefix" ],
"server": [ "DBServer", "DBServerType", "DBName", "DBUser", "DBPass", "DBDirectory", "DBFlags", "DBTablePrefix", "DBPrepared", "DBTypes" ],
"db": [ "DBServer", "DBServerType", "DBName", "DBUser", "DBPass", "DBDirectory", "DBFlags", "DBTablePrefix", "DBPrepared", "DBTypes" ],
"directory": [ "DirectoryPath" ],
"file": [ "FilePath" ],
"domain": [ "LDAPServer", "LDAPUser", "LDAPPass", "LDAPBaseDN" ]
Expand All @@ -110,6 +100,7 @@
[ { "__pf": "get_file_data" }, "EDConnectorFile" ],
[ { "__pf": "get_soap_data" }, "EDConnectorSoap" ],
[ { "__pf": "get_ldap_data" }, "EDConnectorLdap" ],
[ { "__pf": "get_db_data", "DBServerType": "mysql", "DBPrepared": true }, "EDConnectorPreparedMysql" ],
[ { "__pf": "get_db_data", "DBServerType": "sqlite" }, "EDConnectorSqlite" ],
[ { "__pf": "get_db_data", "DBServerType": "mongodb", "__mongo": "MongoDB\\Client" }, "EDConnectorMongodb7" ],
[ { "__pf": "get_db_data", "DBServerType": "mongodb", "__mongo": "MongoClient" }, "EDConnectorMongodb5" ],
Expand Down
8 changes: 6 additions & 2 deletions i18n/en.json
Expand Up @@ -23,12 +23,16 @@
"externaldata-db-incomplete-information": "Error: Incomplete information for this database ID $1 ($2).",
"externaldata-db-could-not-get-url": "Could not get URL $1 after $2 {{PLURAL:$2|try|tries}}.",
"externaldata-db-unknown-type": "Error: Unknown database type $1.",
"externaldata-db-could-not-connect": "Error: Could not connect to database.",
"externaldata-db-could-not-connect": "Error: Could not connect to database ($1).",
"externaldata-db-unknown-database": "Error: Could not select the database specified with ID $1.",
"externaldata-db-no-return-values": "Error: No return values specified.",
"externaldata-db-invalid-query": "The query $1 is invalid.",
"externaldata-db-invalid-query": "The query $1 is invalid ($2).",
"externaldata-db-too-many-joins": "The number of JOIN conditions (now $1) must not exceed the number of tables ($2)",
"externaldata-db-invalid-join": "Invalid JOIN condition $1: every part must contain an \"=\" sign.",
"externaldata-db-empty-rowset": "The query $1 returned an empty rowset.",
"externaldata-db-prepared-not-specified": "Please specify (from=), which prepared statement to use for the database ID $1.",
"externaldata-db-no-such-prepared": "The prepared statement $2 is not set up for the database ID $1.",
"externaldata-odbc-illegal": "The parameter $2 contains an illegal sequence $1. Please stop.",
"externaldata-mongodb-unknown-collection": "Error: Unknown MongoDB collection $1.",
"externaldata-mongodb-aggregation-failed": "MongoDB aggregation failed with error $1",
"externaldata-format-unavailable": "The library $1, required to use the '$2' format without the '$3' option, is missing.",
Expand Down
8 changes: 6 additions & 2 deletions i18n/qqq.json
Expand Up @@ -29,12 +29,16 @@
"externaldata-db-incomplete-information": "Used as error message if not all necessary database connection settings are provided in wiki settings.\n\nDatabase server, database type, database directory, database username and/or database password are not specified.\nParameters:\n* $1 is the database ID,\n* $2 is the name of the missing parameter.",
"externaldata-db-could-not-get-url": "Parameters:\n* $1 - the URL,\n* $2 - number of HTTP tries",
"externaldata-db-unknown-type": "Used as error message when creating a database object with using the specified information. $1 is the database type.",
"externaldata-db-could-not-connect": "Used as error message when connecting to the database system.",
"externaldata-db-could-not-connect": "Used as error message when connecting to the database system. $1 is the error message.",
"externaldata-db-unknown-database": "An error message whe the database set in $edgDBName cannot be selected. $1 is the database id (db parameter).",
"externaldata-db-no-return-values": "Used as error message, if the number of the specified columns is zero.\n\nIf successful, the system returns values in the specified columns.",
"externaldata-db-invalid-query": "Used as error message, if the query has failed. $1 is the query text.",
"externaldata-db-invalid-query": "Used as error message, if the query has failed. $1 is the query text, $2 is the error message from the server.",
"externaldata-db-too-many-joins": "An error message when the number of JOIN conditions exceeds the number of tables. Parameters:\n* $1 is the number of JOIN conditions,\n* $2 is the number of tables.",
"externaldata-db-invalid-join": "An error message for a wrong JOIN condition, any comma-separated part of which should contain a \"=\" sign. $1 is a wrong part.",
"externaldata-db-empty-rowset": "An error message used when an SQL query returns an empty rowset. $1 is an SQL query.",
"externaldata-db-prepared-not-specified": "The error message shown if several prepared statements are set up for the database, but no statement key is provided in the from parameter. $1 is the database ID.",
"externaldata-db-no-such-prepared": "This error message is shown when prepared statements array for the database does not include the provided key. Parameters:\n\n $1 is the database ID,\n\n$2 is the prepared statement key.",
"externaldata-odbc-illegal": "This error message shown if an attempted SQL injection is suspected. $1 is the offending substring, and $2 is the parameter in whach it was found.",
"externaldata-mongodb-unknown-collection": "The error message if #get_db_data can't find the specified \"collection\" when connecting to MongoDB. $1 is the collection name",
"externaldata-mongodb-aggregation-failed": "An error message produced when an aggregation query against a MongoDB collection fails. $1 is the error message.",
"externaldata-format-unavailable": "An error message for a missing PHP library.\n\nParameters:\n* $1 - the name of the missing PHP library\n* $2 - the format that requires it\n* $3 - a parameter for a MediaWiki parser function",
Expand Down
8 changes: 6 additions & 2 deletions i18n/ru.json
Expand Up @@ -28,12 +28,16 @@
"externaldata-db-incomplete-information": "В настройках вики неполная информация для БД ID $1. Отсутствует $2.",
"externaldata-db-could-not-get-url": "Не удалось получить URL $1 после $2 {{PLURAL:$2|попытки|попыток}}.",
"externaldata-db-unknown-type": "Ошибка: Неизвестный тип базы данных $1.",
"externaldata-db-could-not-connect": "ОШИБКА. Не удаётся подключиться к базе данных.",
"externaldata-db-could-not-connect": "ОШИБКА. Не удаётся подключиться к базе данных ($1).",
"externaldata-db-unknown-database": "Ошибка: невозможно выбрать базу данных, указанную в настройках вики для $1.",
"externaldata-db-no-return-values": "ОШИБКА. Не указаны возвращаемые значение.",
"externaldata-db-invalid-query": "Ошибочный запрос $1.",
"externaldata-db-invalid-query": "Ошибочный запрос $1 ($2).",
"externaldata-db-too-many-joins": "Число условий соединения таблиц (сейчас $1) не должно превышать числа таблиц ($2)",
"externaldata-db-invalid-join": "Неверное условие JOIN $1: каждая часть должна содержать знак &laquo;=&raquo;.",
"externaldata-db-empty-rowset": "Запрос $1 не возвратил ни одной строки.",
"externaldata-db-prepared-not-specified": "Укажите (from=), который из заданных длф БД ID $1 подготавливаемых запросов использовать.",
"externaldata-db-no-such-prepared": "Подготавливаемый запрос $2 не задан для БД ID $1.",
"externaldata-odbc-illegal": "В параметре $2 обнаружена недопустимая последовательность $1. Перестаньте.",
"externaldata-mongodb-unknown-collection": "Ошибка: Неизвестная коллекция MongoDB $1.",
"externaldata-mongodb-aggregation-failed": "Ошибка при агрегации MongoDB: $1",
"externaldata-format-unavailable": "Отсутствует библиотека $1, необходимая для использования формата $2 без опции '$3'.",
Expand Down

0 comments on commit d17b824

Please sign in to comment.