Parâmetros para Odbc.DataSource
A função Odbc.DataSource usa dois parâmetros: um connectionString
para o driver e um registro options
que permite substituir vários comportamentos de driver. Por meio do registro de opções, você pode substituir recursos e outras informações relatadas pelo driver, controlar o comportamento do navegador e afetar as consultas SQL geradas pelo mecanismo M.
Os campos de registros de opções compatíveis se enquadram em duas categorias: aquelas que são públicas e sempre disponíveis, e aquelas que só estão disponíveis em um contexto de extensibilidade.
A tabela a seguir descreve os campos públicos no registro de opções.
Campo | Descrição |
---|---|
CommandTimeout |
Um valor de duração que controla por quanto tempo a consulta do servidor tem permissão para ser executada antes do cancelamento. Padrão: 10 minutos |
ConnectionTimeout |
Um valor de duração que controla por quanto tempo é necessário esperar antes de abandonar a tentativa de fazer uma conexão com o servidor. Padrão: 15 segundos |
CreateNavigationProperties |
Um valor lógico que define se as propriedades de navegação nos valores retornados serão geradas. As propriedades de navegação são baseadas em relações de chave estrangeira relatadas pelo driver. Essas propriedades aparecem como colunas "virtuais" que podem ser expandidas no editor de consultas, criando a junção apropriada. Se calcular dependências de chave estrangeira for uma operação cara para o driver, convém definir esse valor como false. Padrão: true |
HierarchicalNavigation |
Um valor lógico que define se as tabelas agrupadas pelos respectivos nomes de esquema serão exibidas. Quando definidas como false, as tabelas são exibidas em uma lista simples em cada banco de dados. Padrão: falso |
SqlCompatibleWindowsAuth |
Um valor lógico que determina se as opções de cadeia de conexão compatíveis com o SQL Server devem ser produzidas para a autenticação do Windows: Trusted_Connection=Yes .Se o driver for compatível com a Autenticação do Windows, mas exigir configurações extras ou alternativas na cadeia de conexão, defina esse valor como false e use o campo de registro de opções CredentialConnectionString descrito na próxima tabela.Padrão: true |
A tabela a seguir descreve os campos de registro de opções que só estão disponíveis por meio da extensibilidade. Campos que não são valores literais simples são descritos em seções posteriores.
Campo | Descrição |
---|---|
AstVisitor |
Um registro que contém uma ou mais substituições para controlar a geração de consulta SQL. O uso mais comum desse campo é fornecer lógica para gerar uma cláusula LIMIT/OFFSET para drivers não compatíveis com TOP. Os campos incluem Constant e LimitClause .Mais informações: Substituir AstVisitor |
CancelQueryExplicitly |
Um valor lógico que instrui o mecanismo M a cancelar explicitamente todas as chamadas em execução por meio do driver ODBC antes de encerrar a conexão com o servidor ODBC. Esse campo é útil em situações em que a execução da consulta é gerenciada independentemente das conexões de rede com o servidor, por exemplo, em algumas implantações do Spark. Na maioria dos casos, esse valor não precisa ser definido porque a consulta no servidor é cancelada quando a conexão de rede com o servidor é encerrada. Padrão: falso |
ClientConnectionPooling |
Um valor lógico que permite o pool de conexões do lado do cliente para o driver ODBC. A maioria dos drivers define esse valor como true. Padrão: falso |
CredentialConnectionString |
Um valor de texto ou registro usado para especificar propriedades de cadeia de conexão relacionadas a credenciais. |
HideNativeQuery |
Um valor lógico que controla se o conector mostra ou não instruções SQL geradas na experiência do usuário no Power Query. Só deve ser definido como true se a fonte de dados de back-end tiver suporte nativo para SQL-92. Padrão: falso |
ImplicitTypeConversions |
Um valor de tabela que contém conversões de tipo implícito compatíveis com o driver ou o servidor de back-end. Os valores nesta tabela são cumulativos às conversões relatadas pelo próprio driver. Esse campo normalmente é usado com o campo SQLGetTypeInfo ao substituir informações de tipo de dados relatadas pelo driver. |
OnError |
Uma função de tratamento de erro que recebe um parâmetro errorRecord do tipo record .Os usos comuns dessa função incluem lidar com falhas de conexão SSL, fornecer um link de download se o driver não for encontrado no sistema e relatar erros de autenticação. |
SoftNumbers |
Permite que o mecanismo M selecione um tipo de dados compatível quando a conversão entre dois tipos numéricos específicos não for declarada como compatível nos recursos SQL_CONVERT_*. Padrão: falso |
SqlCapabilities |
Um registro que fornece várias substituições de recursos de driver e uma maneira de especificar recursos que não são expressos por meio do ODBC 3.8. Mais informações: Substituir SqlCapabilities |
SQLColumns |
Uma função que permite modificar metadados de coluna retornados pela função SQLColumns .Mais informações: Substituir SQLColumns |
SQLGetFunctions |
Um registro que permite substituir valores retornados por chamadas para SQLGetFunctions .Um uso comum desse campo é desabilitar o uso da associação de parâmetros ou especificar que as consultas geradas devem usar CAST em vez de CONVERT. Mais informações: Substituir SQLGetFunctions |
SQLGetInfo |
Um registro que permite substituir valores retornados por chamadas para SQLGetInfo .Mais informações: Substituir SQLGetInfo |
SQLGetTypeInfo |
Uma tabela ou função que retorna uma tabela que substitui as informações de tipo retornadas por SQLGetTypeInfo .Quando o valor é definido como uma tabela, o valor substitui completamente as informações de tipo relatadas pelo driver. SQLGetTypeInfo não será chamado.Quando o valor é definido como uma função, sua função receberá o resultado da chamada original à SQLGetTypeInfo , permitindo que você modifique a tabela.Normalmente, esse campo é usado quando há uma incompatibilidade entre os tipos de dados relatados por SQLGetTypeInfo e SQLColumns .Mais informações: Substituir SQLGetTypeInfo |
SQLTables |
Uma função que permite modificar os metadados da tabela retornados por uma chamada para SQLTables . |
TolerateConcatOverflow |
Permite que a concatenação de valores de texto ocorra mesmo que o resultado possa ser truncado para caber dentro do intervalo de um tipo disponível. Por exemplo, ao concatenar um campo VARCHAR(4000) com um campo VARCHAR(4000) em um sistema compatível com um tamanho VARCHAR maximizado de 4000 e nenhum tipo CLOB, a concatenação é dobrada mesmo que o resultado possa ser truncado. Padrão: falso |
UseEmbeddedDriver |
(uso interno): um valor lógico que controla se o driver ODBC deve ser carregado de um diretório local (usando nova funcionalidade definida na especificação ODBC 4.0). Esse valor geralmente é definido apenas por conectores criados pela Microsoft integrados ao Power Query. Quando definido como false, o gerenciador de driver ODBC do sistema é usado para localizar e carregar o driver. A maioria dos conectores não precisa definir esse campo. Padrão: falso |
O campo AstVisitor
é definido por meio do registro de opções Odbc.DataSource. Ele é usado para modificar instruções SQL geradas para cenários de consulta específicos.
Observação
Os drivers compatíveis com cláusulas LIMIT e OFFSET (em vez de TOP) precisarão substituir LimitClause
por AstVisitor
.
A substituição desse valor foi preterida e pode ser removida de implementações futuras.
Esse campo é uma função que recebe dois argumentos Int64.Type
(skip
, take
) e retorna um registro com dois campos de texto (Text
, Location
).
LimitClause = (skip as nullable number, take as number) as record => ...
O parâmetro skip
é o número de linhas a serem ignoradas (ou seja, o argumento para OFFSET). Se um deslocamento não for especificado, o valor ignorado será nulo. Se o driver for compatível com LIMIT, mas não aceitar OFFSET, a função LimitClause
deverá retornar um erro não simplificado (...) quando o valor ignorado for maior que 0.
O parâmetro take
é o número de linhas a serem consideradas (ou seja, o argumento para LIMIT).
O campo Text
do resultado contém o texto SQL a ser adicionado à consulta gerada.
O campo Location
especifica onde inserir a cláusula. A tabela a seguir descreve os valores compatíveis.
Valor | Descrição | Exemplo |
---|---|---|
AfterQuerySpecification |
A cláusula LIMIT é colocada no final do SQL gerado. Essa é a sintaxe LIMIT mais compatível. |
SELECT a, b, c FROM table WHERE a > 10 LIMIT 5 |
BeforeQuerySpecification |
A cláusula LIMIT é colocada antes da instrução SQL gerada. | LIMIT 5 ROWS SELECT a, b, c FROM table WHERE a > 10 |
AfterSelect |
LIMIT fica após a instrução SELECT e depois de qualquer modificador (como DISTINCT). | SELECT DISTINCT LIMIT 5 a, b, c FROM table WHERE a > 10 |
AfterSelectBeforeModifiers |
LIMIT fica após a instrução SELECT, mas antes de qualquer modificador (como DISTINCT). | SELECT LIMIT 5 DISTINCT a, b, c FROM table WHERE a > 10 |
O snippet de código a seguir fornece uma implementação de LimitClause para um driver que espera uma cláusula LIMIT, com um OFFSET opcional, no seguinte formato: [OFFSET <offset> ROWS] LIMIT <row_count>
LimitClause = (skip, take) =>
let
offset = if (skip > 0) then Text.Format("OFFSET #{0} ROWS", {skip}) else "",
limit = if (take <> null) then Text.Format("LIMIT #{0}", {take}) else ""
in
[
Text = Text.Format("#{0} #{1}", {offset, limit}),
Location = "AfterQuerySpecification"
]
O snippet de código a seguir fornece uma implementação LimitClause
para um driver que aceita LIMIT, mas não OFFSET. Formato: LIMIT <row_count>
.
LimitClause = (skip, take) =>
if (skip > 0) then error "Skip/Offset not supported"
else
[
Text = Text.Format("LIMIT #{0}", {take}),
Location = "AfterQuerySpecification"
]
Campo | Detalhes |
---|---|
FractionalSecondsScale |
Um valor numérico que varia de 1 a 7 e indica o número de casas decimais disponíveis para valores de milissegundos. Esse valor deve ser definido por conectores que habilitam a dobragem de consultas em valores de datetime. Padrão: nulo |
PrepareStatements |
Um valor lógico que indica que as instruções devem ser preparadas usando SQLPrepare. Padrão: falso |
SupportsTop |
Um valor lógico que indica que o driver é compatível com a cláusula TOP para limitar o número de linhas retornadas. Padrão: falso |
StringLiteralEscapeCharacters |
Uma lista de valores de texto que especificam os caracteres a serem usados ao escapar literais de cadeia de caracteres e expressões LIKE. Exemplo: {""} Padrão: nulo |
SupportsDerivedTable |
Um valor lógico que indica que o driver é compatível com tabelas derivadas (submarcas). Esse valor é considerado true para drivers que definem seu nível de conformidade como SQL_SC_SQL92_FULL (relatado pelo driver ou substituído com a configuração sql92Conformance. Para todos os outros níveis de conformidade, esse valor usa false como padrão. Se o driver não relatar o nível de conformidade SQL_SC_SQL92_FULL, mas fizer tabelas derivadas compatíveis, defina esse valor como true. A compatibilidade com tabelas derivadas é necessária para muitos cenários do DirectQuery. |
SupportsNumericLiterals |
Um valor lógico que indica se o SQL gerado deve incluir valores de literais numéricos. Quando definidos como false, os valores numéricos são sempre especificados usando a associação de parâmetro. Padrão: falso |
SupportsStringLiterals |
Um valor lógico que indica se o SQL gerado deve incluir valores de literais de cadeia de caracteres. Quando definidos como false, os valores de cadeia de caracteres são sempre especificados usando a associação de parâmetro. Padrão: falso |
SupportsOdbcDateLiterals |
Um valor lógico que indica se o SQL gerado deve incluir valores de literais de data. Quando definidos como false, os valores de data são sempre especificados usando a associação de parâmetro. Padrão: falso |
SupportsOdbcTimeLiterals |
Um valor lógico que indica se o SQL gerado deve incluir valores de literais de hora. Quando definidos como false, os valores de hora são sempre especificados usando a associação de parâmetro. Padrão: falso |
SupportsOdbcTimestampLiterals |
Um valor lógico que indica se o SQL gerado deve incluir valores de literais de carimbo de data/hora. Quando definidos como false, os valores de carimbo de data/hora são sempre especificados usando a associação de parâmetro. Padrão: falso |
SQLColumns
é um manipulador de funções que recebe os resultados de uma chamada ODBC para SQLColumns. O parâmetro de origem contém uma tabela com as informações de tipo de dados. Normalmente, essa substituição é usada para corrigir incompatibilidades de tipo de dados entre chamadas SQLGetTypeInfo
e SQLColumns
.
Para saber mais sobre o formato do parâmetro de tabela de origem, acesse Função SQLColumns.
Esse campo é usado para substituir valores SQLFunctions
retornados por um driver ODBC. Ele contém um registro cujos nomes de campo são iguais às constantes FunctionId
definidas para a função ODBC SQLGetFunctions. Constantes numéricas para cada um desses campos podem ser encontradas na especificação ODBC.
Campo | Detalhes |
---|---|
SQL_CONVERT_FUNCTIONS |
Indica quais funções são aceitas ao fazer conversões de tipo. Por padrão, o Mecanismo M tenta usar a função CONVERT. Os drivers que preferem o uso do CAST podem substituir esse valor para relatar que há compatibilidade apenas com SQL_FN_CVT_CAST (valor numérico de 0x2). |
SQL_API_SQLBINDCOL |
Um valor lógico (true/false) que indica se o mecanismo de mashup deve usar a API SQLBindCol ao recuperar dados. Quando definido como false, SQLGetData é usado. Padrão: falso |
O snippet de código a seguir mostra um exemplo que diz explicitamente ao mecanismo M para usar CAST em vez de CONVERT.
SQLGetFunctions = [
SQL_CONVERT_FUNCTIONS = 0x2 /* SQL_FN_CVT_CAST */
]
Esse campo é usado para substituir valores SQLGetInfo
retornados por um driver ODBC. Ele contém um registro cujos campos são nomes são iguais às constantes InfoType
definidas para a função ODBC SQLGetInfo. Constantes numéricas para cada um desses campos podem ser encontradas na especificação ODBC. A lista completa de InfoTypes
verificados pode ser encontrada nos arquivos de rastreamento do mecanismo de mashup.
A tabela a seguir contém propriedades SQLGetInfo
normalmente substituídas:
Campo | Detalhes |
---|---|
SQL_SQL_CONFORMANCE |
Um valor inteiro que indica o nível do SQL-92 compatível com o driver: (1) SQL_SC_SQL92_ENTRY: em conformidade com o SQL-92 de nível de entrada. (2) SQL_SC_FIPS127_2_TRANSITIONAL: em conformidade com o FIPS 127-2 de nível de transição. (4) SQL_SC_ SQL92_INTERMEDIATE" em conformidade com o SQL-92 de nível intermediário. (8) SQL_SC_SQL92_FULL: em conformidade com o SQL-92 de nível completo. Em cenários de Power Query, o conector é usado em um modo somente leitura. A maioria dos drivers relata um nível de conformidade SQL_SC_SQL92_FULL e substitui o comportamento de geração de SQL específico usando propriedades SQLGetInfo e SQLGetFunctions . |
SQL_SQL92_PREDICATES |
Um bitmask que enumera os predicados compatíveis em uma instrução SELECT, conforme definido no SQL-92. Acesse Constantes SQL_SP_* na especificação ODBC. |
SQL_AGGREGATE_FUNCTIONS |
Compatibilidade com enumeração de bitmask para funções de agregação. SQL_AF_ALL SQL_AF_AVG SQL_AF_COUNT SQL_AF_DISTINCT SQL_AF_MAX SQL_AF_MIN SQL_AF_SUM Acesse Constantes SQL_AF_* na especificação ODBC. |
SQL_GROUP_BY |
Um valor inteiro que especifica o relacionamento entre as colunas em uma cláusula GROUP BY e as colunas não agregadas na lista de seleção: SQL_GB_COLLATE: uma cláusula COLLATE pode ser especificada no final de cada coluna de agrupamento. SQL_GB_NOT_SUPPORTED: cláusulas GROUP BY não são compatíveis. SQL_GB_GROUP_BY_EQUALS_SELECT: a cláusula GROUP BY deve conter todas as colunas não agregadas na lista de seleção. Ela não pode conter nenhuma outra coluna. Por exemplo, SELECT DEPT, MAX(SALARY) FROM EMPLOYEE GROUP BY DEPT. SQL_GB_GROUP_BY_CONTAINS_SELECT: a cláusula GROUP BY deve conter todas as colunas não agregadas na lista de seleção. Ela pode conter colunas que não estão na lista de seleção. Por exemplo, SELECT DEPT, MAX(WAGE) FROM EMPLOYEE GROUP BY DEPT, AGE. SQL_GB_NO_RELATION: as colunas na cláusula GROUP BY e na lista de seleção não estão relacionadas. O significado de colunas não agrupadas e não agregadas na lista de seleção depende da fonte de dados. Por exemplo, SELECT DEPT, MAX(SALARY) FROM EMPLOYEE GROUP BY DEPT. Acesse Constantes SQL_GB_* na especificação ODBC. |
Esta função auxiliar pode ser usada para criar valores de bitmask de uma lista de valores inteiros:
Flags = (flags as list) =>
let
Loop = List.Generate(
()=> [i = 0, Combined = 0],
each [i] < List.Count(flags),
each [i = [i]+1, Combined =*Number.BitwiseOr([Combined], flags{i})],
each [Combined]),
Result = List.Last(Loop, 0)
in
Result;
SQLGetTypeInfo
pode ser especificado de duas maneiras:
- Um valor fixo
table
que contém as mesmas informações de tipo que uma chamada ODBC paraSQLGetTypeInfo
. - Uma função que aceita um argumento de tabela e retorna uma tabela. O argumento contém os resultados originais da chamada ODBC para
SQLGetTypeInfo
. Sua implementação de função pode modificar ou adicionar a esta tabela.
A primeira abordagem é usada para substituir completamente os valores retornados pelo driver ODBC. A segunda abordagem será usada se você quiser adicionar ou modificar esses valores.
Para saber mais sobre o formato dos tipos de parâmetro de tabela e o valor de retorno esperado, acesse Referência da função SQLGetTypeInfo.
O snippet de código a seguir fornece uma implementação estática para SQLGetTypeInfo
.
SQLGetTypeInfo = #table(
{ "TYPE_NAME", "DATA_TYPE", "COLUMN_SIZE", "LITERAL_PREF", "LITERAL_SUFFIX", "CREATE_PARAS", "NULLABLE", "CASE_SENSITIVE", "SEARCHABLE", "UNSIGNED_ATTRIBUTE", "FIXED_PREC_SCALE", "AUTO_UNIQUE_VALUE", "LOCAL_TYPE_NAME", "MINIMUM_SCALE", "MAXIMUM_SCALE", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "NUM_PREC_RADIX", "INTERNAL_PRECISION", "USER_DATA_TYPE" }, {
{ "char", 1, 65535, "'", "'", "max. length", 1, 1, 3, null, 0, null, "char", null, null, -8, null, null, 0, 0 },
{ "int8", -5, 19, "'", "'", null, 1, 0, 2, 0, 10, 0, "int8", 0, 0, -5, null, 2, 0, 0 },
{ "bit", -7, 1, "'", "'", null, 1, 1, 3, null, 0, null, "bit", null, null, -7, null, null, 0, 0 },
{ "bool", -7, 1, "'", "'", null, 1, 1, 3, null, 0, null, "bit", null, null, -7, null, null, 0, 0 },
{ "date", 9, 10, "'", "'", null, 1, 0, 2, null, 0, null, "date", null, null, 9, 1, null, 0, 0 },
{ "numeric", 3, 28, null, null, null, 1, 0, 2, 0, 0, 0, "numeric", 0, 0, 2, null, 10, 0, 0 },
{ "float8", 8, 15, null, null, null, 1, 0, 2, 0, 0, 0, "float8", null, null, 6, null, 2, 0, 0 },
{ "float8", 6, 17, null, null, null, 1, 0, 2, 0, 0, 0, "float8", null, null, 6, null, 2, 0, 0 },
{ "uuid", -11, 37, null, null, null, 1, 0, 2, null, 0, null, "uuid", null, null, -11, null, null, 0, 0 },
{ "int4", 4, 10, null, null, null, 1, 0, 2, 0, 0, 0, "int4", 0, 0, 4, null, 2, 0, 0 },
{ "text", -1, 65535, "'", "'", null, 1, 1, 3, null, 0, null, "text", null, null, -10, null, null, 0, 0 },
{ "lo", -4, 255, "'", "'", null, 1, 0, 2, null, 0, null, "lo", null, null, -4, null, null, 0, 0 },
{ "numeric", 2, 28, null, null, "precision, scale", 1, 0, 2, 0, 10, 0, "numeric", 0, 6, 2, null, 10, 0, 0 },
{ "float4", 7, 9, null, null, null, 1, 0, 2, 0, 10, 0, "float4", null, null, 7, null, 2, 0, 0 },
{ "int2", 5, 19, null, null, null, 1, 0, 2, 0, 10, 0, "int2", 0, 0, 5, null, 2, 0, 0 },
{ "int2", -6, 5, null, null, null, 1, 0, 2, 0, 10, 0, "int2", 0, 0, 5, null, 2, 0, 0 },
{ "timestamp", 11, 26, "'", "'", null, 1, 0, 2, null, 0, null, "timestamp", 0, 38, 9, 3, null, 0, 0 },
{ "date", 91, 10, "'", "'", null, 1, 0, 2, null, 0, null, "date", null, null, 9, 1, null, 0, 0 },
{ "timestamp", 93, 26, "'", "'", null, 1, 0, 2, null, 0, null, "timestamp", 0, 38, 9, 3, null, 0, 0 },
{ "bytea", -3, 255, "'", "'", null, 1, 0, 2, null, 0, null, "bytea", null, null, -3, null, null, 0, 0 },
{ "varchar", 12, 65535, "'", "'", "max. length", 1, 0, 2, null, 0, null, "varchar", null, null, -9, null, null, 0, 0 },
{ "char", -8, 65535, "'", "'", "max. length", 1, 1, 3, null, 0, null, "char", null, null, -8, null, null, 0, 0 },
{ "text", -10, 65535, "'", "'", "max. length", 1, 1, 3, null, 0, null, "text", null, null, -10, null, null, 0, 0 },
{ "varchar", -9, 65535, "'", "'", "max. length", 1, 1, 3, null, 0, null, "varchar", null, null, -9, null, null, 0, 0 },
{ "bpchar", -8, 65535, "'", "'", "max. length", 1, 1, 3, null, 0, null, "bpchar", null, null, -9, null, null, 0, 0 } }
);
Os snippets de código a seguir acrescentam o tipo bpchar
aos tipos existentes retornados pelo driver.
SQLGetTypeInfo = (types as table) as table =>
let
newTypes = #table(
{
"TYPE_NAME",
"DATA_TYPE",
"COLUMN_SIZE",
"LITERAL_PREF",
"LITERAL_SUFFIX",
"CREATE_PARAS",
"NULLABLE",
"CASE_SENSITIVE",
"SEARCHABLE",
"UNSIGNED_ATTRIBUTE",
"FIXED_PREC_SCALE",
"AUTO_UNIQUE_VALUE",
"LOCAL_TYPE_NAME",
"MINIMUM_SCALE",
"MAXIMUM_SCALE",
"SQL_DATA_TYPE",
"SQL_DATETIME_SUB",
"NUM_PREC_RADIX",
"INTERNAL_PRECISION",
"USER_DATA_TYPE"
},
// we add a new entry for each type we want to add
{
{
"bpchar",
-8,
65535,
"'",
"'",
"max. length",
1,
1,
3,
null,
0,
null,
"bpchar",
null,
null,
-9,
null,
null,
0,
0
}
}),
append = Table.Combine({types, newTypes})
in
append;
A cadeia de conexão para o driver ODBC é definida usando o primeiro argumento para as funções Odbc.DataSource e Odbc.Query. O valor pode ser texto ou um registro M. Ao usar o registro, cada campo no registro se tornará uma propriedade na cadeia de conexão. Todas as cadeias de conexão exigem um campo Driver
(ou campo DSN
, se você exigir que os usuários pré-configurem um DSN no nível do sistema). As propriedades relacionadas à credencial são definidas separadamente. Outras propriedades são específicas do driver.
O snippet de código abaixo mostra a definição de uma nova função de fonte de dados, criação do registro ConnectionString
e invocação da função Odbc.DataSource.
[DataSource.Kind="SqlODBC", Publish="SqlODBC.Publish"]
shared SqlODBC.Contents = (server as text) =>
let
ConnectionString = [
Driver = "SQL Server Native Client 11.0",
Server = server,
MultiSubnetFailover = "Yes",
ApplicationIntent = "ReadOnly",
APP = "PowerBICustomConnector"
],
OdbcDatasource = Odbc.DataSource(ConnectionString)
in
OdbcDatasource;