Выполнение именных запросов в Афине

Мы хотим выполнить параметризованный запрос в Athena, используя javascript sdk by aws.

Кажется, что запрос по имени Афины может быть способом, но документация кажется очень загадочной, чтобы понять, как это сделать.

Было бы здорово, если кто-то может помочь нам сделать следующее

  • Каков рекомендуемый способ избежать внедрения sql в athena?
  • Создайте параметризованный запрос, например SELECT c FROM Country c WHERE c.name = :name
  • Передайте значение параметра name
  • Выполните этот запрос

Ответ 1

Именованные запросы - странная особенность Афины, которая, к сожалению, ни к чему не приводит.

Афина не поддерживает готовые заявления, как многие РСУБД. Есть библиотеки SQL с поддержкой для расширения параметров на стороне клиента - у меня есть опыт работы с Sequel для Ruby, к сожалению, я не могу дать вам совет по JavaScript.

Однако ускользнуть от Афины на диалекте SQL не очень сложно. В идентификаторах двойные кавычки должны быть экранированы как две двойные кавычки, а в литеральных строках одинарные кавычки должны быть экранированы как одинарные кавычки. Другие типы данных просто должны быть чистыми, например, только цифры для целых чисел.

Кроме того, имейте в виду, что в Athena опасность внедрения SQL-кода отличается от ситуации в RDBMS: Athena не может удалить ваши данные. Если вы правильно настроили свои разрешения IAM, пользователь не сможет даже удалить таблицы, и даже если вы по какой-то причине запускаете запросы с пользователем, которому разрешено удалять таблицы, таблицы являются просто метаданными и могут быть легко настроены заново.

Ответ 2

Несмотря на то, что можно запускать запрос от конечного пользователя, важно иметь в виду, что AWS Athena имеет некоторые ограничения на обслуживание и реализует только подмножество SQL.

Athena в конце будет запрашивать некоторые файлы S3 в кодах, где количество файлов влияет на выполнение запросов, а после завершения запроса конечным результатом будет файл в промежуточном ведре.

Обычно я использую структуру, подобную следующей, для выполнения запросов в Афине.

const AWS = require('aws-sdk');
const async = require('async')
const athena = new AWS.Athena();

let myTable = 'my_tablename';
let myBucket = 'my_bucket_name';
let myDatabase = 'my_database_name';

async.auto({
  execute_query: function(callback) {
   let params = {
      QueryString: 'select count(*) as line_count from '+myTable,
      ResultConfiguration: { 
        OutputLocation: myBucket
      },
      QueryExecutionContext: {
        Database: myDatabase
      }
    };        
    athena.startQueryExecution(params, callback);
  },
  fetch_results: ['execute_query', function(results, callback) {
    let executionData = results.execute_query;
    executionData.MaxResults=50;
    let retryCount=1;
    let maxRetries=300;
    async.forever(
        function(next) {
          athena.getQueryResults(executionData, function(err, data) {
            if (err && err.code==='InvalidRequestException') {                  
              if (err.message.match(/.*: (RUNNING|QUEUED)/)) {
               retryCount=retryCount+1;
                setTimeout(() => {
                  return next(retryCount>maxRetries ? 'max retries reached for query on: '+myTable : null);                
                },
                1000);
              } else {
                callback(err);
              }
            } else {
              callback(null,data.ResultSet.Rows[1].Data[1].VarCharValue);
            }
          });  
        },
        callback
    );    
  }],
  function(err, results) {
       console.log('err = ', err);
       console.log('results = ', results);
    }
});

Если вам нужна дополнительная информация, пожалуйста, спросите в комментариях, и я постараюсь улучшить.