Неверный синтаксис рядом с @indexName.щеголеватый - PullRequest
2 голосов
/ 05 апреля 2019

Это кажется странным поведением, но следующий код выдает ошибку:

public async Task RebuildIndex(string tableName, string indexName)
{
    await _dbConnection.ExecuteAsync($@"
        alter index @indexName on @tableName rebuild;", 
    new
    {
        indexName = indexName,
        tableName = tableName
    });
}

Сообщение об ошибке:

System.Data.SqlClient.SqlException (0x80131904): Неправильный синтаксис около конструкции "@indexName".
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
   at System.Data.SqlClient.SqlCommand.CompleteAsyncExecuteReader()
   at System.Data.SqlClient.SqlCommand.EndExecuteNonQueryInternal(IAsyncResult asyncResult)
   at System.Data.SqlClient.SqlCommand.EndExecuteNonQuery(IAsyncResult asyncResult)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
   at Dapper.SqlMapper.ExecuteImplAsync(IDbConnection cnn, CommandDefinition command, Object param) in C:\projects\dapper\Dapper\SqlMapper.Async.cs:line 678
   at Railways.DbManager.Repositories.DbmIndexDefragmentationRepository.RebuildIndex(String tableName, String indexName) in C:\Railways\asu-itk-core\Railways\Railways.DbManager.Repositories\DbmIndexDefragmentationRepository.cs:line 48
   at Railways.DBManager.Services.IndexDefragmentationService.DefragIndexes() in C:\Railways\asu-itk-core\Railways\Railways.DBManager.Services\IndexDefragmentationService.cs:line 41
ClientConnectionId:7db4e7f6-e01d-4671-9fe3-e22dcb388cd4
Error Number:102,State:1,Class:15

Что здесь может быть не так?

Я просто передаю параметр, и это должно работать.

Может быть, я что-то упустил? Может ли кто-нибудь предложить решение?

1 Ответ

3 голосов
/ 05 апреля 2019

Вы не сможете параметризовать имена целевых объектов, используемые в инструкциях SQL, то есть имена таблиц и имена индексов не могут быть параметризованы. Это не просто ограничение Dapper - например, ADO.Net и sp_executesql также не могут параметризовать таблицы. (теоретически параметризация защищает не только от атак с использованием SQL-инъекций, но и улучшает кэширование плана выполнения на основе точных типов данных - очевидно, что кэширование плана невозможно, если целевая таблица является динамической).

В вашем случае вам нужно будет выполнить собственную проверку SQL-инъекций (при необходимости - весьма необычно для имен индексов и таблиц исходить от ненадежного пользователя), а затем просто подставить имя в оператор SQL. например, через строковую интерполяцию или String.Format.

Если вы действительно принимаете имена таблиц или индексов от ненадежных пользователей и нуждаетесь в защите от атак с использованием SQL-инъекций, вы можете воспользоваться советом Аарона Бетранда и сначала проверить наличие таблицы в sys.tables и индекс в sys.indexes перед выполнением оператора SQL.

Редактировать

Причина, по которой вы можете параметризовать имя таблицы в запросах к system таблицам, таким как sys.tables и DMVs, таким как sys.dm_db_index_physical_stats, заключается в том, что здесь имя таблицы или другого объекта является значением в столбце. Но точно так же вы не сможете параметризовать имя системной таблицы или самого DMV.

...