Parámetros para Odbc.DataSource
La función Odbc.DataSource toma dos parámetros, uno de connectionString
para el controlador y un registro options
que le permite anular varios comportamientos del controlador. Con el registro de opciones puede anular las funcionalidades y otra información que notifica el controlador, controlar el comportamiento del navegador y afectar a las consultas SQL generadas por el motor M.
Los campos de registros de opciones admitidos se dividen en dos categorías: los que son públicos y están siempre disponibles, y los que solo están disponibles en un contexto de extensibilidad.
En la tabla siguiente se describen los campos públicos del registro de opciones.
Campo | Descripción |
---|---|
CommandTimeout |
Un valor de duración que controla durante cuánto tiempo se permite la ejecución de la consulta del lado servidor antes de que se cancele. Valor predeterminado: 10 minutos |
ConnectionTimeout |
Un valor de duración que controla cuánto tiempo de espera es necesario antes de abandonar un intento de establecer una conexión con el servidor. Valor predeterminado: 15 segundos. |
CreateNavigationProperties |
Un valor lógico que establece si se deben generar propiedades de navegación en las tablas devueltas. Las propiedades de navegación se basan en las relaciones de clave externa notificadas por el controlador. Estas propiedades se muestran como columnas "virtuales" que se pueden expandir en el editor de consultas, creando la combinación adecuada. Si calcular las dependencias de clave externa es una operación costosa para el controlador, es posible que desee establecer este valor en false. Valor predeterminado: true |
HierarchicalNavigation |
Un valor lógico que establece si se deben ver las tablas agrupadas por sus nombres de esquema. Cuando se establece en false, las tablas se muestran en una lista plana bajo cada base de datos. Valor predeterminado: false |
SqlCompatibleWindowsAuth |
Un valor lógico que determina si se debe generar una cadena de conexión compatible con SQL Server cuando se usa la autenticación de Windows—Trusted_Connection=Yes .Si el controlador admite la autenticación de Windows, pero requiere una configuración adicional o alternativa en la cadena de conexión, debe establecer este valor en false y usar el campo de registro de opciones CredentialConnectionString descrito en la tabla siguiente.Valor predeterminado: true |
En la tabla siguiente se describen los campos de registro de opciones que solo están disponibles a través de la extensibilidad. Los campos que no son valores literales simples se describen en secciones posteriores.
Campo | Descripción |
---|---|
AstVisitor |
Registro que contiene una o varias anulaciones para controlar la generación de consultas SQL. El uso más común de este campo es proporcionar lógica para generar una cláusula LIMIT/OFFSET para los controladores que no admiten TOP. Los campos incluyen Constant y LimitClause .Más información: Anulación de AstVisitor |
CancelQueryExplicitly |
Valor lógico que indica al motor M que cancele explícitamente las llamadas en ejecución a través del controlador ODBC antes de finalizar la conexión con el servidor ODBC. Este campo es útil en situaciones en las que la ejecución de consultas se administra independientemente de las conexiones de red al servidor, por ejemplo, en algunas implementaciones de Spark. En la mayoría de los casos, no es necesario establecer este valor porque la consulta en el servidor se cancela cuando finaliza la conexión de red al servidor. Valor predeterminado: false |
ClientConnectionPooling |
Valor lógico que permite la agrupación de conexiones del lado cliente para el controlador ODBC. La mayoría de los controladores querrán establecer este valor en true. Valor predeterminado: false |
CredentialConnectionString |
Valor de texto o registro usado para especificar propiedades de cadena de conexión relacionadas con credenciales. |
HideNativeQuery |
Valor lógico que controla si el conector muestra o no instrucciones SQL generadas en la experiencia del usuario de Power Query. Esto solo debe establecerse en true si el origen de datos back-end admite de forma nativa SQL-92. Valor predeterminado: false |
ImplicitTypeConversions |
Valor de tabla que contiene conversiones de tipos implícitas compatibles con el controlador o el servidor back-end. Los valores de esta tabla se agregan a las conversiones notificadas por el propio controlador. Este campo se usa normalmente con el campo SQLGetTypeInfo al anular la información del tipo de datos notificada por el controlador. |
OnError |
Función de control de errores que recibe un parámetro errorRecord de tipo record .Entre los usos comunes de esta función se incluyen el control de errores de conexión SSL, lo que proporciona un vínculo de descarga si el controlador no se encuentra en el sistema y notifica errores de autenticación. |
SoftNumbers |
Permite al motor M seleccionar un tipo de datos compatible cuando la conversión entre dos tipos numéricos específicos no se declara como compatible con las funcionalidades de SQL_CONVERT_*. Valor predeterminado: false |
SqlCapabilities |
Un registro que proporciona varias anulaciones de las funcionalidades del controlador y una manera de especificar funcionalidades que no se expresan a través de ODBC 3.8. Más información: Anulación de SqlCapabilities |
SQLColumns |
Función que permite modificar los metadatos de columna devueltos por la función SQLColumns .Más información: Anulación de SQLColumns |
SQLGetFunctions |
Un registro que permite anular los valores devueltos por llamadas a SQLGetFunctions .Un uso común de este campo es deshabilitar el uso del enlace de parámetros o especificar que las consultas generadas deben usar CAST en lugar de CONVERT. Más información: Anulación de SQLGetFunctions |
SQLGetInfo |
Un registro que permite anular los valores devueltos por llamadas a SQLGetInfo .Más información: Anulación de SQLGetInfo |
SQLGetTypeInfo |
Una tabla o función que devuelve una tabla que anula la información de tipo devuelta por SQLGetTypeInfo .Cuando el valor se establece en una tabla, el valor reemplaza completamente la información de tipo notificada por el controlador. No se llamará a SQLGetTypeInfo .Cuando el valor se establece en una función, la función recibirá el resultado de la llamada original a SQLGetTypeInfo , lo que le permite modificar la tabla.Este campo se usa normalmente cuando hay una discrepancia entre los tipos de datos notificados por SQLGetTypeInfo y SQLColumns .Más información: Anulación de SQLGetTypeInfo |
SQLTables |
Función que permite modificar los metadatos de la tabla devueltos por una llamada a SQLTables . |
TolerateConcatOverflow |
Permite que se produzca la concatenación de valores de texto incluso si el resultado se puede truncar para ajustarse al intervalo de un tipo disponible. Por ejemplo, al concatenar un campo VARCHAR(4000) con un campo VARCHAR(4000) en un sistema que admita un tamaño de VARCHAR maximizado de 4000 y ningún tipo CLOB, la concatenación se plega aunque el resultado pueda truncarse. Valor predeterminado: false |
UseEmbeddedDriver |
(uso interno): valor lógico que controla si el controlador ODBC se debe cargar desde un directorio local (mediante la nueva funcionalidad definida en la especificación ODBC 4.0). Por lo general, este valor solo se establece mediante conectores creados por Microsoft que se incluyen con Power Query. Cuando se establece en false, el administrador de controladores ODBC del sistema se usa para buscar y cargar el controlador. La mayoría de los conectores no deben tener que establecer este campo. Valor predeterminado: false |
El campo AstVisitor
se establece a través del registro de opciones Odbc.DataSource. Se usa para modificar instrucciones SQL generadas para escenarios de consulta específicos.
Nota
Los controladores que admiten cláusulas LIMIT y OFFSET (en lugar de TOP) querrán proporcionar una anulación LimitClause
para AstVisitor
.
Proporcionar una anulación para este valor ha quedado en desuso y se puede quitar de futuras implementaciones.
Este campo es una función que recibe dos argumentos Int64.Type
(skip
, take
) y devuelve un registro con dos campos de texto (Text
, Location
).
LimitClause = (skip as nullable number, take as number) as record => ...
El parámetro skip
es el número de filas que se van a omitir (es decir, el argumento para OFFSET). Si no se especifica un desplazamiento, el valor de skip será null. Si el controlador admite LIMIT, pero no admite OFFSET, la función LimitClause
debe devolver un error no implementado (...) cuando skip sea mayor que 0.
El parámetro take
es el número de filas que se van a tomar (es decir, el argumento para LIMIT).
El campo Text
del resultado contiene el texto SQL que se va a agregar a la consulta generada.
El campo Location
especifica dónde insertar la cláusula. En la tabla siguiente se describen los valores admitidos.
Valor | Descripción | Ejemplo |
---|---|---|
AfterQuerySpecification |
La cláusula LIMIT se coloca al final del SQL generado. Esta es la sintaxis LIMIT más compatible. |
SELECT a, b, c Tabla FROM WHERE a > 10 LIMIT 5 |
BeforeQuerySpecification |
La cláusula LIMIT se coloca antes de la instrucción SQL generada. | LIMIT 5 ROWS SELECT a, b, c Tabla FROM WHERE a > 10 |
AfterSelect |
LIMIT va después de la instrucción SELECT y después de cualquier otro modificador (como DISTINCT). | SELECT DISTINCT LIMIT 5 a, b, c Tabla FROM WHERE a > 10 |
AfterSelectBeforeModifiers |
LIMIT va después de la instrucción SELECT, pero antes de cualquier modificador (como DISTINCT). | SELECT LIMIT 5 DISTINCT a, b, c Tabla FROM WHERE a > 10 |
El fragmento de código siguiente proporciona una implementación LimitClause para un controlador que espera una cláusula LIMIT, con un OFFSET opcional, con el siguiente 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"
]
El siguiente fragmento de código proporciona una implementación de LimitClause
para un controlador que admite LIMIT, pero no OFFSET. Format: 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 | Detalles |
---|---|
FractionalSecondsScale |
Valor numérico comprendido entre 1 y 7 que indica el número de posiciones decimales admitidas para valores de milisegundos. Este valor debe ser establecido por los conectores que deseen habilitar el plegado de consultas sobre valores datetime. Valor predeterminado: null |
PrepareStatements |
Valor lógico que indica que las instrucciones se deben preparar mediante SQLPrepare. Valor predeterminado: false |
SupportsTop |
Valor lógico que indica que el controlador admite la cláusula TOP para limitar el número de filas devueltas. Valor predeterminado: false |
StringLiteralEscapeCharacters |
Lista de valores de texto que especifican los caracteres que se van a usar al escapar literales de cadena y expresiones LIKE. Ejemplo: {""} Valor predeterminado: null |
SupportsDerivedTable |
Valor lógico que indica que el controlador admite tablas derivadas (subselecciones). Se supone que este valor es true para los controladores que establecen su nivel de conformidad en SQL_SC_SQL92_FULL (notificados por el controlador o reemplazados con el ajuste de Sql92Conformance. Para todos los demás niveles de conformidad, este valor tiene como valor predeterminado false. Si el controlador no notifica el nivel de cumplimiento SQL_SC_SQL92_FULL, pero admite tablas derivadas, establezca este valor en true. Se requiere compatibilidad con tablas derivadas para muchos escenarios de DirectQuery. |
SupportsNumericLiterals |
Valor lógico que indica si el SQL generado debe incluir valores literales numéricos. Cuando se establece en false, los valores numéricos siempre se especifican mediante el enlace de parámetros. Valor predeterminado: false |
SupportsStringLiterals |
Valor lógico que indica si el SQL generado debe incluir valores literales de cadena. Cuando se establece en false, los valores de cadena siempre se especifican mediante el enlace de parámetros. Valor predeterminado: false |
SupportsOdbcDateLiterals |
Valor lógico que indica si el SQL generado debe incluir valores literales de fecha. Cuando se establece en false, los valores de fecha siempre se especifican mediante el enlace de parámetros. Valor predeterminado: false |
SupportsOdbcTimeLiterals |
Valor lógico que indica si el SQL generado debe incluir valores literales de hora. Cuando se establece en false, los valores de hora siempre se especifican mediante el enlace de parámetros. Valor predeterminado: false |
SupportsOdbcTimestampLiterals |
Valor lógico que indica si el SQL generado debe incluir valores literales de marca de tiempo. Cuando se establece en false, los valores de marca de tiempo siempre se especifican mediante el enlace de parámetros. Valor predeterminado: false |
SQLColumns
es un controlador de funciones que recibe los resultados de una llamada ODBC a SQLColumns. El parámetro de origen contiene una tabla con la información del tipo de datos. Esta anulación se usa normalmente para corregir errores de coincidencia de tipos de datos entre las llamadas a SQLGetTypeInfo
y SQLColumns
.
Para obtener más información sobre el formato del parámetro de la tabla de origen, consulte Función SQLColumns.
Este campo se usa para anular valores de SQLFunctions
devueltos por un controlador ODBC. Contiene un registro cuyos nombres de campo son iguales a las constantes de FunctionId
definidas para la función ODBC SQLGetFunctions. Las constantes numéricas para cada uno de estos campos se pueden encontrar en la especificación de ODBC.
Campo | Detalles |
---|---|
SQL_CONVERT_FUNCTIONS |
Indica qué funciones se admiten al realizar conversiones de tipos. De forma predeterminada, el motor M intenta usar la función CONVERT. Los controladores que prefieren el uso de CAST pueden anular este valor para informar de que solo se admite SQL_FN_CVT_CAST (valor numérico de 0x2). |
SQL_API_SQLBINDCOL |
Valor lógico (true/false) que indica si el motor de mashup debe usar la API SQLBindCol al recuperar datos. Cuando se establece en false, se usa SQLGetData en su lugar. Valor predeterminado: false |
El siguiente fragmento de código proporciona un ejemplo que indica explícitamente al motor M que se debe usar CAST en lugar de CONVERT.
SQLGetFunctions = [
SQL_CONVERT_FUNCTIONS = 0x2 /* SQL_FN_CVT_CAST */
]
Este campo se usa para anular valores de SQLGetInfo
devueltos por un controlador ODBC. Contiene un registro cuyos campos son nombres iguales a las constantes de InfoType
definidas para la función SQLGetInfo. Las constantes numéricas para cada uno de estos campos se pueden encontrar en la especificación de ODBC. La lista completa de InfoTypes
que se comprueba se puede encontrar en los archivos de seguimiento del motor de mashup.
La tabla siguiente contiene propiedades de SQLGetInfo
que se suelen anular:
Campo | Detalles |
---|---|
SQL_SQL_CONFORMANCE |
Valor entero que indica el nivel de SQL-92 admitido por el controlador: (1) SQL_SC_SQL92_ENTRY: compatible con SQL-92 a nivel de entrada. (2) SQL_SC_FIPS127_2_TRANSITIONAL: compatible con FIPS 127-2 a nivel de transición. (4) SQL_SC_ SQL92_INTERMEDIATE": compatible con SQL-92 a nivel intermedio. (8) SQL_SC_SQL92_FULL: compatible con SQL-92 a nivel completo. En escenarios de Power Query, el conector se usa en un modo de solo lectura. La mayoría de los controladores querrán notificar un nivel de cumplimiento de SQL_SC_SQL92_FULL y anular el comportamiento específico de la generación de SQL mediante las propiedades SQLGetInfo y SQLGetFunctions . |
SQL_SQL92_PREDICATES |
Máscara de bits que enumera los predicados admitidos en una instrucción SELECT, tal como se define en SQL-92. Vaya a constantes SQL_SP_* en la especificación ODBC. |
SQL_AGGREGATE_FUNCTIONS |
Máscara de bits que enumera la compatibilidad para las funciones de agregación. SQL_AF_ALL SQL_AF_AVG SQL_AF_COUNT SQL_AF_DISTINCT SQL_AF_MAX SQL_AF_MIN SQL_AF_SUM Vaya a constantes SQL_AF_* en la especificación ODBC. |
SQL_GROUP_BY |
Valor entero que especifica la relación entre las columnas de la cláusula GROUP BY y las columnas no agregadas de la lista de selección: SQL_GB_COLLATE: se puede especificar una cláusula COLLATE al final de cada columna de agrupación. SQL_GB_NOT_SUPPORTED: no se admiten cláusulas GROUP BY. SQL_GB_GROUP_BY_EQUALS_SELECT: la cláusula GROUP BY debe contener todas las columnas no agregadas de la lista de selección. No puede contener ninguna otra columna. Por ejemplo, SELECT DEPT, MAX(SALARY) FROM EMPLOYEE GROUP BY DEPT. SQL_GB_GROUP_BY_CONTAINS_SELECT: la cláusula GROUP BY debe contener todas las columnas no agregadas de la lista de selección. Puede contener columnas que no están en la lista de selección. Por ejemplo, SELECT DEPT, MAX(SALARY) FROM EMPLOYEE GROUP BY DEPT, AGE. SQL_GB_NO_RELATION: las columnas de la cláusula GROUP BY y la lista de selección no están relacionadas. El significado de las columnas no agrupadas y no agregadas en la lista de selección depende del origen de datos. Por ejemplo, SELECT DEPT, SALARY FROM EMPLOYEE GROUP BY DEPT, AGE. Vaya a constantes SQL_GB_* en la especificación ODBC. |
La siguiente función auxiliar se puede usar para crear valores de máscara de bits a partir de una lista de valores enteros:
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
se puede especificar de dos maneras:
- Un valor
table
fijo que contiene la misma información de tipo que una llamada ODBC aSQLGetTypeInfo
. - Función que acepta un argumento de tabla y devuelve una tabla. El argumento contiene los resultados originales de la llamada ODBC a
SQLGetTypeInfo
. La implementación de la función puede modificar o agregar a esta tabla.
El primer enfoque se usa para anular completamente los valores devueltos por el controlador ODBC. El segundo enfoque se usa si desea agregar o modificar estos valores.
Para obtener más información sobre el formato del parámetro de tabla de tipos y el valor devuelto esperado, consulte la referencia de la función SQLGetTypeInfo.
El fragmento de código siguiente proporciona una implementación 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 } }
);
Los fragmentos de código siguientes anexan el tipo bpchar
a los tipos existentes devueltos por el controlador.
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;
La cadena de conexión del controlador ODBC se establece mediante el primer argumento de las funciones Odbc.DataSource y Odbc.Query. El valor puede ser texto o un registro M. Al usar el registro, cada campo del registro se convertirá en una propiedad en la cadena de conexión. Todas las cadenas de conexión requieren un campo Driver
(o un campo DSN
si necesita que los usuarios configuren previamente un DSN en el nivel de sistema). Las propiedades relacionadas con credenciales se establecen por separado. Otras propiedades son específicas del controlador.
El fragmento de código siguiente muestra la definición de una nueva función de origen de datos, la creación del registro ConnectionString
y la invocación de la función 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;