diff --git a/sql-odbc/.gitignore b/sql-odbc/.gitignore
index 849c3e99b7..ecaefb1c61 100644
--- a/sql-odbc/.gitignore
+++ b/sql-odbc/.gitignore
@@ -57,4 +57,5 @@ CTestTestfile.cmake
/sdk-build64/
/cmake-build64/
/src/PowerBIConnector/bin/Debug/
-/src/PowerBIConnector/obj/
\ No newline at end of file
+/src/PowerBIConnector/obj/
+/src/PowerBIConnector/.vs/
diff --git a/sql-odbc/docs/user/img/pbi_auth.png b/sql-odbc/docs/user/img/pbi_auth.png
index 12e1af8ed6..0795d63d95 100644
Binary files a/sql-odbc/docs/user/img/pbi_auth.png and b/sql-odbc/docs/user/img/pbi_auth.png differ
diff --git a/sql-odbc/docs/user/img/pbi_error_conn.png b/sql-odbc/docs/user/img/pbi_error_conn.png
new file mode 100644
index 0000000000..87f908a397
Binary files /dev/null and b/sql-odbc/docs/user/img/pbi_error_conn.png differ
diff --git a/sql-odbc/docs/user/img/pbi_error_driver_not_installed.png b/sql-odbc/docs/user/img/pbi_error_driver_not_installed.png
new file mode 100644
index 0000000000..b5059bc0b4
Binary files /dev/null and b/sql-odbc/docs/user/img/pbi_error_driver_not_installed.png differ
diff --git a/sql-odbc/docs/user/power_bi_support.md b/sql-odbc/docs/user/power_bi_support.md
index 38b8259a42..46dd618829 100644
--- a/sql-odbc/docs/user/power_bi_support.md
+++ b/sql-odbc/docs/user/power_bi_support.md
@@ -32,7 +32,7 @@
-* Select authentication option and click on **Connect**.
+* Select authentication option. Enter credentials if required and click on **Connect**.
@@ -40,4 +40,19 @@
-* Click on **Load**.
\ No newline at end of file
+* Click on **Load**.
+
+## Troubleshooting
+
+* If you get an following error, please install [Open Distro For Elasticsearch SQL ODBC Driver](https://opendistro.github.io/for-elasticsearch-docs/docs/sql/odbc/).
+
+
+
+* If you get an following error,
+
+
+
+1. Check if host and port values are correct.
+2. Check if auth credentials are correct.
+3. Check if server is running.
+
diff --git a/sql-odbc/src/PowerBIConnector/Diagnostics.pqm b/sql-odbc/src/PowerBIConnector/Diagnostics.pqm
new file mode 100644
index 0000000000..ca10c3cf98
--- /dev/null
+++ b/sql-odbc/src/PowerBIConnector/Diagnostics.pqm
@@ -0,0 +1,275 @@
+let
+ Diagnostics.LogValue = (prefix, value) => Diagnostics.Trace(TraceLevel.Information, prefix & ": " & (try Diagnostics.ValueToText(value) otherwise ""), value),
+ Diagnostics.LogValue2 = (prefix, value, result, optional delayed) => Diagnostics.Trace(TraceLevel.Information, prefix & ": " & Diagnostics.ValueToText(value), result, delayed),
+ Diagnostics.LogFailure = (text, function) =>
+ let
+ result = try function()
+ in
+ if result[HasError] then Diagnostics.LogValue2(text, result[Error], () => error result[Error], true) else result[Value],
+
+ Diagnostics.WrapFunctionResult = (innerFunction as function, outerFunction as function) as function =>
+ Function.From(Value.Type(innerFunction), (list) => outerFunction(() => Function.Invoke(innerFunction, list))),
+
+ Diagnostics.WrapHandlers = (handlers as record) as record =>
+ Record.FromList(
+ List.Transform(
+ Record.FieldNames(handlers),
+ (h) => Diagnostics.WrapFunctionResult(Record.Field(handlers, h), (fn) => Diagnostics.LogFailure(h, fn))),
+ Record.FieldNames(handlers)),
+
+ Diagnostics.ValueToText = (value) =>
+ let
+ _canBeIdentifier = (x) =>
+ let
+ keywords = {"and", "as", "each", "else", "error", "false", "if", "in", "is", "let", "meta", "not", "otherwise", "or", "section", "shared", "then", "true", "try", "type" },
+ charAlpha = (c as number) => (c>= 65 and c <= 90) or (c>= 97 and c <= 122) or c=95,
+ charDigit = (c as number) => c>= 48 and c <= 57
+ in
+ try
+ charAlpha(Character.ToNumber(Text.At(x,0)))
+ and
+ List.MatchesAll(
+ Text.ToList(x),
+ (c)=> let num = Character.ToNumber(c) in charAlpha(num) or charDigit(num)
+ )
+ and not
+ List.MatchesAny( keywords, (li)=> li=x )
+ otherwise
+ false,
+
+ Serialize.Binary = (x) => "#binary(" & Serialize(Binary.ToList(x)) & ") ",
+
+ Serialize.Date = (x) => "#date(" &
+ Text.From(Date.Year(x)) & ", " &
+ Text.From(Date.Month(x)) & ", " &
+ Text.From(Date.Day(x)) & ") ",
+
+ Serialize.Datetime = (x) => "#datetime(" &
+ Text.From(Date.Year(DateTime.Date(x))) & ", " &
+ Text.From(Date.Month(DateTime.Date(x))) & ", " &
+ Text.From(Date.Day(DateTime.Date(x))) & ", " &
+ Text.From(Time.Hour(DateTime.Time(x))) & ", " &
+ Text.From(Time.Minute(DateTime.Time(x))) & ", " &
+ Text.From(Time.Second(DateTime.Time(x))) & ") ",
+
+ Serialize.Datetimezone =(x) => let
+ dtz = DateTimeZone.ToRecord(x)
+ in
+ "#datetimezone(" &
+ Text.From(dtz[Year]) & ", " &
+ Text.From(dtz[Month]) & ", " &
+ Text.From(dtz[Day]) & ", " &
+ Text.From(dtz[Hour]) & ", " &
+ Text.From(dtz[Minute]) & ", " &
+ Text.From(dtz[Second]) & ", " &
+ Text.From(dtz[ZoneHours]) & ", " &
+ Text.From(dtz[ZoneMinutes]) & ") ",
+
+ Serialize.Duration = (x) => let
+ dur = Duration.ToRecord(x)
+ in
+ "#duration(" &
+ Text.From(dur[Days]) & ", " &
+ Text.From(dur[Hours]) & ", " &
+ Text.From(dur[Minutes]) & ", " &
+ Text.From(dur[Seconds]) & ") ",
+
+ Serialize.Function = (x) => _serialize_function_param_type(
+ Type.FunctionParameters(Value.Type(x)),
+ Type.FunctionRequiredParameters(Value.Type(x)) ) &
+ " as " &
+ _serialize_function_return_type(Value.Type(x)) &
+ " => (...) ",
+
+ Serialize.List = (x) => "{" &
+ List.Accumulate(x, "", (seed,item) => if seed="" then Serialize(item) else seed & ", " & Serialize(item)) &
+ "} ",
+
+ Serialize.Logical = (x) => Text.From(x),
+
+ Serialize.Null = (x) => "null",
+
+ Serialize.Number = (x) =>
+ let Text.From = (i as number) as text =>
+ if Number.IsNaN(i) then "#nan" else
+ if i=Number.PositiveInfinity then "#infinity" else
+ if i=Number.NegativeInfinity then "-#infinity" else
+ Text.From(i)
+ in
+ Text.From(x),
+
+ Serialize.Record = (x) => "[ " &
+ List.Accumulate(
+ Record.FieldNames(x),
+ "",
+ (seed,item) =>
+ (if seed="" then Serialize.Identifier(item) else seed & ", " & Serialize.Identifier(item)) & " = " & Serialize(Record.Field(x, item))
+ ) &
+ " ] ",
+
+ Serialize.Table = (x) => "#table( type " &
+ _serialize_table_type(Value.Type(x)) &
+ ", " &
+ Serialize(Table.ToRows(x)) &
+ ") ",
+
+ Serialize.Text = (x) => """" &
+ _serialize_text_content(x) &
+ """",
+
+ _serialize_text_content = (x) => let
+ escapeText = (n as number) as text => "#(#)(" & Text.PadStart(Number.ToText(n, "X", "en-US"), 4, "0") & ")"
+ in
+ List.Accumulate(
+ List.Transform(
+ Text.ToList(x),
+ (c) => let n=Character.ToNumber(c) in
+ if n = 9 then "#(#)(tab)" else
+ if n = 10 then "#(#)(lf)" else
+ if n = 13 then "#(#)(cr)" else
+ if n = 34 then """""" else
+ if n = 35 then "#(#)(#)" else
+ if n < 32 then escapeText(n) else
+ if n < 127 then Character.FromNumber(n) else
+ escapeText(n)
+ ),
+ "",
+ (s,i)=>s&i
+ ),
+
+ Serialize.Identifier = (x) =>
+ if _canBeIdentifier(x) then
+ x
+ else
+ "#""" &
+ _serialize_text_content(x) &
+ """",
+
+ Serialize.Time = (x) => "#time(" &
+ Text.From(Time.Hour(x)) & ", " &
+ Text.From(Time.Minute(x)) & ", " &
+ Text.From(Time.Second(x)) & ") ",
+
+ Serialize.Type = (x) => "type " & _serialize_typename(x),
+
+
+ _serialize_typename = (x, optional funtype as logical) => /* Optional parameter: Is this being used as part of a function signature? */
+ let
+ isFunctionType = (x as type) => try if Type.FunctionReturn(x) is type then true else false otherwise false,
+ isTableType = (x as type) => try if Type.TableSchema(x) is table then true else false otherwise false,
+ isRecordType = (x as type) => try if Type.ClosedRecord(x) is type then true else false otherwise false,
+ isListType = (x as type) => try if Type.ListItem(x) is type then true else false otherwise false
+ in
+
+ if funtype=null and isTableType(x) then _serialize_table_type(x) else
+ if funtype=null and isListType(x) then "{ " & @_serialize_typename( Type.ListItem(x) ) & " }" else
+ if funtype=null and isFunctionType(x) then "function " & _serialize_function_type(x) else
+ if funtype=null and isRecordType(x) then _serialize_record_type(x) else
+
+ if x = type any then "any" else
+ let base = Type.NonNullable(x) in
+ (if Type.IsNullable(x) then "nullable " else "") &
+ (if base = type anynonnull then "anynonnull" else
+ if base = type binary then "binary" else
+ if base = type date then "date" else
+ if base = type datetime then "datetime" else
+ if base = type datetimezone then "datetimezone" else
+ if base = type duration then "duration" else
+ if base = type logical then "logical" else
+ if base = type none then "none" else
+ if base = type null then "null" else
+ if base = type number then "number" else
+ if base = type text then "text" else
+ if base = type time then "time" else
+ if base = type type then "type" else
+
+ /* Abstract types: */
+ if base = type function then "function" else
+ if base = type table then "table" else
+ if base = type record then "record" else
+ if base = type list then "list" else
+
+ "any /*Actually unknown type*/"),
+
+ _serialize_table_type = (x) =>
+ let
+ schema = Type.TableSchema(x)
+ in
+ "table " &
+ (if Table.IsEmpty(schema) then "" else
+ "[" & List.Accumulate(
+ List.Transform(
+ Table.ToRecords(Table.Sort(schema,"Position")),
+ each Serialize.Identifier(_[Name]) & " = " & _[Kind]),
+ "",
+ (seed,item) => (if seed="" then item else seed & ", " & item )
+ ) & "] " ),
+
+ _serialize_record_type = (x) =>
+ let flds = Type.RecordFields(x)
+ in
+ if Record.FieldCount(flds)=0 then "record" else
+ "[" & List.Accumulate(
+ Record.FieldNames(flds),
+ "",
+ (seed,item) =>
+ seed &
+ (if seed<>"" then ", " else "") &
+ (Serialize.Identifier(item) & "=" & _serialize_typename(Record.Field(flds,item)[Type]) )
+ ) &
+ (if Type.IsOpenRecord(x) then ",..." else "") &
+ "]",
+
+ _serialize_function_type = (x) => _serialize_function_param_type(
+ Type.FunctionParameters(x),
+ Type.FunctionRequiredParameters(x) ) &
+ " as " &
+ _serialize_function_return_type(x),
+
+ _serialize_function_param_type = (t,n) =>
+ let
+ funsig = Table.ToRecords(
+ Table.TransformColumns(
+ Table.AddIndexColumn( Record.ToTable( t ), "isOptional", 1 ),
+ { "isOptional", (x)=> x>n } ) )
+ in
+ "(" &
+ List.Accumulate(
+ funsig,
+ "",
+ (seed,item)=>
+ (if seed="" then "" else seed & ", ") &
+ (if item[isOptional] then "optional " else "") &
+ Serialize.Identifier(item[Name]) & " as " & _serialize_typename(item[Value], true) )
+ & ")",
+
+ _serialize_function_return_type = (x) => _serialize_typename(Type.FunctionReturn(x), true),
+
+ Serialize = (x) as text =>
+ if x is binary then try Serialize.Binary(x) otherwise "null /*serialize failed*/" else
+ if x is date then try Serialize.Date(x) otherwise "null /*serialize failed*/" else
+ if x is datetime then try Serialize.Datetime(x) otherwise "null /*serialize failed*/" else
+ if x is datetimezone then try Serialize.Datetimezone(x) otherwise "null /*serialize failed*/" else
+ if x is duration then try Serialize.Duration(x) otherwise "null /*serialize failed*/" else
+ if x is function then try Serialize.Function(x) otherwise "null /*serialize failed*/" else
+ if x is list then try Serialize.List(x) otherwise "null /*serialize failed*/" else
+ if x is logical then try Serialize.Logical(x) otherwise "null /*serialize failed*/" else
+ if x is null then try Serialize.Null(x) otherwise "null /*serialize failed*/" else
+ if x is number then try Serialize.Number(x) otherwise "null /*serialize failed*/" else
+ if x is record then try Serialize.Record(x) otherwise "null /*serialize failed*/" else
+ if x is table then try Serialize.Table(x) otherwise "null /*serialize failed*/" else
+ if x is text then try Serialize.Text(x) otherwise "null /*serialize failed*/" else
+ if x is time then try Serialize.Time(x) otherwise "null /*serialize failed*/" else
+ if x is type then try Serialize.Type(x) otherwise "null /*serialize failed*/" else
+ "[#_unable_to_serialize_#]"
+ in
+ try Serialize(value) otherwise ""
+in
+ [
+ LogValue = Diagnostics.LogValue,
+ LogValue2 = Diagnostics.LogValue2,
+ LogFailure = Diagnostics.LogFailure,
+ WrapFunctionResult = Diagnostics.WrapFunctionResult,
+ WrapHandlers = Diagnostics.WrapHandlers,
+ ValueToText = Diagnostics.ValueToText
+ ]
\ No newline at end of file
diff --git a/sql-odbc/src/PowerBIConnector/OdbcConstants.pqm b/sql-odbc/src/PowerBIConnector/OdbcConstants.pqm
new file mode 100644
index 0000000000..144e525413
--- /dev/null
+++ b/sql-odbc/src/PowerBIConnector/OdbcConstants.pqm
@@ -0,0 +1,1253 @@
+// values from https://github.com/Microsoft/ODBC-Specification/blob/master/Windows/inc/sqlext.h
+[
+ Flags = (flags as list) =>
+ if (List.IsEmpty(flags)) then 0 else
+ let
+ Loop = List.Generate(()=> [i = 0, Combined = flags{0}],
+ each [i] < List.Count(flags),
+ each [Combined = Number.BitwiseOr([Combined], flags{i}), i = [i]+1],
+ each [Combined]),
+ Result = List.Last(Loop)
+ in
+ Result,
+
+ SQL_HANDLE =
+ [
+ ENV = 1,
+ DBC = 2,
+ STMT = 3,
+ DESC = 4
+ ],
+
+ RetCode =
+ [
+ SUCCESS = 0,
+ SUCCESS_WITH_INFO = 1,
+ ERROR = -1,
+ INVALID_HANDLE = -2,
+ NO_DATA = 100
+ ],
+
+ SQL_CONVERT =
+ [
+ BIGINT = 53,
+ BINARY = 54,
+ BIT = 55,
+ CHAR = 56,
+ DATE = 57,
+ DECIMAL = 58,
+ DOUBLE = 59,
+ FLOAT = 60,
+ INTEGER = 61,
+ LONGVARCHAR = 62,
+ NUMERIC = 63,
+ REAL = 64,
+ SMALLINT = 65,
+ TIME = 66,
+ TIMESTAMP = 67,
+ TINYINT = 68,
+ VARBINARY = 69,
+ VARCHAR = 70,
+ LONGVARBINARY = 71
+ ],
+
+ SQL_ROW =
+ [
+ PROCEED = 0,
+ IGNORE = 1,
+ SUCCESS = 0,
+ DELETED = 1,
+ UPDATED = 2,
+ NOROW = 3,
+ ADDED = 4,
+ ERROR = 5,
+ SUCCESS_WITH_INFO = 6
+ ],
+
+SQL_CVT =
+[
+ //None = 0,
+
+ CHAR = 0x00000001,
+ NUMERIC = 0x00000002,
+ DECIMAL = 0x00000004,
+ INTEGER = 0x00000008,
+ SMALLINT = 0x00000010,
+ FLOAT = 0x00000020,
+ REAL = 0x00000040,
+ DOUBLE = 0x00000080,
+ VARCHAR = 0x00000100,
+ LONGVARCHAR = 0x00000200,
+ BINARY = 0x00000400,
+ VARBINARY = 0x00000800,
+ BIT = 0x00001000,
+ TINYINT = 0x00002000,
+ BIGINT = 0x00004000,
+ DATE = 0x00008000,
+ TIME = 0x00010000,
+ TIMESTAMP = 0x00020000,
+ LONGVARBINARY = 0x00040000,
+ INTERVAL_YEAR_MONTH = 0x00080000,
+ INTERVAL_DAY_TIME = 0x00100000,
+ WCHAR = 0x00200000,
+ WLONGVARCHAR = 0x00400000,
+ WVARCHAR = 0x00800000,
+ GUID = 0x01000000
+],
+
+ STMT =
+ [
+ CLOSE = 0,
+ DROP = 1,
+ UNBIND = 2,
+ RESET_PARAMS = 3
+ ],
+
+ SQL_MAX =
+ [
+ NUMERIC_LEN = 16
+ ],
+
+ SQL_IS =
+ [
+ POINTER = -4,
+ INTEGER = -6,
+ UINTEGER = -5,
+ SMALLINT = -8
+ ],
+
+ //SQL Server specific defines
+ //
+ SQL_HC = // from Odbcss.h
+ [
+ OFF = 0, // FOR BROWSE columns are hidden
+ ON = 1 // FOR BROWSE columns are exposed
+ ],
+
+ SQL_NB = // from Odbcss.h
+ [
+ OFF = 0, // NO_BROWSETABLE is off
+ ON = 1 // NO_BROWSETABLE is on
+ ],
+
+ // SQLColAttributes driver specific defines.
+ // SQLSet/GetDescField driver specific defines.
+ // Microsoft has 1200 thru 1249 reserved for Microsoft SQL Server driver usage.
+ //
+ SQL_CA_SS = // from Odbcss.h
+ [
+ BASE = 1200, // SQL_CA_SS_BASE
+
+ COLUMN_HIDDEN = 1200 + 11, // Column is hidden (FOR BROWSE)
+ COLUMN_KEY = 1200 + 12, // Column is key column (FOR BROWSE)
+ VARIANT_TYPE = 1200 + 15,
+ VARIANT_SQL_TYPE = 1200 + 16,
+ VARIANT_SERVER_TYPE = 1200 + 17
+
+ ],
+
+ SQL_SOPT_SS = // from Odbcss.h
+ [
+ BASE = 1225, // SQL_SOPT_SS_BASE
+ HIDDEN_COLUMNS = 1225 + 2, // Expose FOR BROWSE hidden columns
+ NOBROWSETABLE = 1225 + 3 // Set NOBROWSETABLE option
+ ],
+
+ SQL_COMMIT = 0, //Commit
+ SQL_ROLLBACK = 1, //Abort
+
+ //static public readonly IntPtr SQL_AUTOCOMMIT_OFF = IntPtr.Zero;
+ //static public readonly IntPtr SQL_AUTOCOMMIT_ON = new IntPtr(1);
+
+ SQL_TRANSACTION =
+ [
+ READ_UNCOMMITTED = 0x00000001,
+ READ_COMMITTED = 0x00000002,
+ REPEATABLE_READ = 0x00000004,
+ SERIALIZABLE = 0x00000008,
+ SNAPSHOT = 0x00000020 // VSDD 414121: SQL_TXN_SS_SNAPSHOT == 0x20 (sqlncli.h)
+ ],
+
+ SQL_PARAM =
+ [
+ TYPE_UNKNOWN = 0, // SQL_PARAM_TYPE_UNKNOWN
+ INPUT = 1, // SQL_PARAM_INPUT
+ INPUT_OUTPUT = 2, // SQL_PARAM_INPUT_OUTPUT
+ RESULT_COL = 3, // SQL_RESULT_COL
+ OUTPUT = 4, // SQL_PARAM_OUTPUT
+ RETURN_VALUE = 5 // SQL_RETURN_VALUE
+ ],
+
+ SQL_DESC =
+ [
+ // from sql.h (ODBCVER >= 3.0)
+ //
+ COUNT = 1001,
+ TYPE = 1002,
+ LENGTH = 1003,
+ OCTET_LENGTH_PTR = 1004,
+ PRECISION = 1005,
+ SCALE = 1006,
+ DATETIME_INTERVAL_CODE = 1007,
+ NULLABLE = 1008,
+ INDICATOR_PTR = 1009,
+ DATA_PTR = 1010,
+ NAME = 1011,
+ UNNAMED = 1012,
+ OCTET_LENGTH = 1013,
+ ALLOC_TYPE = 1099,
+
+ // from sqlext.h (ODBCVER >= 3.0)
+ //
+ CONCISE_TYPE = SQL_COLUMN[TYPE],
+ DISPLAY_SIZE = SQL_COLUMN[DISPLAY_SIZE],
+ UNSIGNED = SQL_COLUMN[UNSIGNED],
+ UPDATABLE = SQL_COLUMN[UPDATABLE],
+ AUTO_UNIQUE_VALUE = SQL_COLUMN[AUTO_INCREMENT],
+
+ TYPE_NAME = SQL_COLUMN[TYPE_NAME],
+ TABLE_NAME = SQL_COLUMN[TABLE_NAME],
+ SCHEMA_NAME = SQL_COLUMN[OWNER_NAME],
+ CATALOG_NAME = SQL_COLUMN[QUALIFIER_NAME],
+
+ BASE_COLUMN_NAME = 22,
+ BASE_TABLE_NAME = 23,
+
+ NUM_PREC_RADIX = 32
+ ],
+
+ // ODBC version 2.0 style attributes
+ // All IdentifierValues are ODBC 1.0 unless marked differently
+ //
+ SQL_COLUMN =
+ [
+ COUNT = 0,
+ NAME = 1,
+ TYPE = 2,
+ LENGTH = 3,
+ PRECISION = 4,
+ SCALE = 5,
+ DISPLAY_SIZE = 6,
+ NULLABLE = 7,
+ UNSIGNED = 8,
+ MONEY = 9,
+ UPDATABLE = 10,
+ AUTO_INCREMENT = 11,
+ CASE_SENSITIVE = 12,
+ SEARCHABLE = 13,
+ TYPE_NAME = 14,
+ TABLE_NAME = 15, // (ODBC 2.0)
+ OWNER_NAME = 16, // (ODBC 2.0)
+ QUALIFIER_NAME = 17, // (ODBC 2.0)
+ LABEL = 18
+ ],
+
+ // values from sqlext.h
+ SQL_SQL92_RELATIONAL_JOIN_OPERATORS =
+ [
+ CORRESPONDING_CLAUSE = 0x00000001, // SQL_SRJO_CORRESPONDING_CLAUSE
+ CROSS_JOIN = 0x00000002, // SQL_SRJO_CROSS_JOIN
+ EXCEPT_JOIN = 0x00000004, // SQL_SRJO_EXCEPT_JOIN
+ FULL_OUTER_JOIN = 0x00000008, // SQL_SRJO_FULL_OUTER_JOIN
+ INNER_JOIN = 0x00000010, // SQL_SRJO_INNER_JOIN
+ INTERSECT_JOIN = 0x00000020, // SQL_SRJO_INTERSECT_JOIN
+ LEFT_OUTER_JOIN = 0x00000040, // SQL_SRJO_LEFT_OUTER_JOIN
+ NATURAL_JOIN = 0x00000080, // SQL_SRJO_NATURAL_JOIN
+ RIGHT_OUTER_JOIN = 0x00000100, // SQL_SRJO_RIGHT_OUTER_JOIN
+ UNION_JOIN = 0x00000200 // SQL_SRJO_UNION_JOIN
+ ],
+
+ // values from sqlext.h
+ SQL_QU =
+ [
+ SQL_QU_DML_STATEMENTS = 0x00000001,
+ SQL_QU_PROCEDURE_INVOCATION = 0x00000002,
+ SQL_QU_TABLE_DEFINITION = 0x00000004,
+ SQL_QU_INDEX_DEFINITION = 0x00000008,
+ SQL_QU_PRIVILEGE_DEFINITION = 0x00000010
+ ],
+
+ // values from sql.h
+ SQL_OJ_CAPABILITIES =
+ [
+ LEFT = 0x00000001, // SQL_OJ_LEFT
+ RIGHT = 0x00000002, // SQL_OJ_RIGHT
+ FULL = 0x00000004, // SQL_OJ_FULL
+ NESTED = 0x00000008, // SQL_OJ_NESTED
+ NOT_ORDERED = 0x00000010, // SQL_OJ_NOT_ORDERED
+ INNER = 0x00000020, // SQL_OJ_INNER
+ ALL_COMPARISON_OPS = 0x00000040 //SQL_OJ_ALLCOMPARISION+OPS
+ ],
+
+ SQL_UPDATABLE =
+ [
+ READONLY = 0, // SQL_ATTR_READ_ONLY
+ WRITE = 1, // SQL_ATTR_WRITE
+ READWRITE_UNKNOWN = 2 // SQL_ATTR_READWRITE_UNKNOWN
+ ],
+
+ SQL_IDENTIFIER_CASE =
+ [
+ UPPER = 1, // SQL_IC_UPPER
+ LOWER = 2, // SQL_IC_LOWER
+ SENSITIVE = 3, // SQL_IC_SENSITIVE
+ MIXED = 4 // SQL_IC_MIXED
+ ],
+
+ // Uniqueness parameter in the SQLStatistics function
+ SQL_INDEX =
+ [
+ UNIQUE = 0,
+ ALL = 1
+ ],
+
+ // Reserved parameter in the SQLStatistics function
+ SQL_STATISTICS_RESERVED =
+ [
+ QUICK = 0, // SQL_QUICK
+ ENSURE = 1 // SQL_ENSURE
+ ],
+
+ // Identifier type parameter in the SQLSpecialColumns function
+ SQL_SPECIALCOLS =
+ [
+ BEST_ROWID = 1, // SQL_BEST_ROWID
+ ROWVER = 2 // SQL_ROWVER
+ ],
+
+ // Scope parameter in the SQLSpecialColumns function
+ SQL_SCOPE =
+ [
+ CURROW = 0, // SQL_SCOPE_CURROW
+ TRANSACTION = 1, // SQL_SCOPE_TRANSACTION
+ SESSION = 2 // SQL_SCOPE_SESSION
+ ],
+
+ SQL_NULLABILITY =
+ [
+ NO_NULLS = 0, // SQL_NO_NULLS
+ NULLABLE = 1, // SQL_NULLABLE
+ UNKNOWN = 2 // SQL_NULLABLE_UNKNOWN
+ ],
+
+ SQL_SEARCHABLE =
+ [
+ UNSEARCHABLE = 0, // SQL_UNSEARCHABLE
+ LIKE_ONLY = 1, // SQL_LIKE_ONLY
+ ALL_EXCEPT_LIKE = 2, // SQL_ALL_EXCEPT_LIKE
+ SEARCHABLE = 3 // SQL_SEARCHABLE
+ ],
+
+ SQL_UNNAMED =
+ [
+ NAMED = 0, // SQL_NAMED
+ UNNAMED = 1 // SQL_UNNAMED
+ ],
+ // todo:move
+ // internal constants
+ // not odbc specific
+ //
+ HANDLER =
+ [
+ IGNORE = 0x00000000,
+ THROW = 0x00000001
+ ],
+
+ // values for SQLStatistics TYPE column
+ SQL_STATISTICSTYPE =
+ [
+ TABLE_STAT = 0, // TABLE Statistics
+ INDEX_CLUSTERED = 1, // CLUSTERED index statistics
+ INDEX_HASHED = 2, // HASHED index statistics
+ INDEX_OTHER = 3 // OTHER index statistics
+ ],
+
+ // values for SQLProcedures PROCEDURE_TYPE column
+ SQL_PROCEDURETYPE =
+ [
+ UNKNOWN = 0, // procedure is of unknow type
+ PROCEDURE = 1, // procedure is a procedure
+ FUNCTION = 2 // procedure is a function
+ ],
+
+ // private constants
+ // to define data types (see below)
+ //
+ SIGNED_OFFSET = -20, // SQL_SIGNED_OFFSET
+ UNSIGNED_OFFSET = -22, // SQL_UNSIGNED_OFFSET
+
+ // C Data Types
+ SQL_C =
+ [
+ CHAR = 1,
+ WCHAR = -8,
+ SLONG = 4 + SIGNED_OFFSET,
+ ULONG = 4 + UNSIGNED_OFFSET,
+ SSHORT = 5 + SIGNED_OFFSET,
+ USHORT = 5 + UNSIGNED_OFFSET,
+ FLOAT = 7,
+ DOUBLE = 8,
+ BIT = -7,
+ STINYINT = -6 + SIGNED_OFFSET,
+ UTINYINT = -6 + UNSIGNED_OFFSET,
+ SBIGINT = -5 + SIGNED_OFFSET,
+ UBIGINT = -5 + UNSIGNED_OFFSET,
+ BINARY = -2,
+ TIMESTAMP = 11,
+
+ TYPE_DATE = 91,
+ TYPE_TIME = 92,
+ TYPE_TIMESTAMP = 93,
+
+ NUMERIC = 2,
+ GUID = -11,
+ DEFAULT = 99,
+ ARD_TYPE = -99
+ ],
+
+ // SQL Data Types
+ SQL_TYPE =
+ [
+ // Base data types (sql.h)
+ UNKNOWN = 0,
+ NULL = 0,
+ CHAR = 1,
+ NUMERIC = 2,
+ DECIMAL = 3,
+ INTEGER = 4,
+ SMALLINT = 5,
+ FLOAT = 6,
+ REAL = 7,
+ DOUBLE = 8,
+ DATETIME = 9, // V3 Only
+ VARCHAR = 12,
+
+ // Unicode types (sqlucode.h)
+ WCHAR = -8,
+ WVARCHAR = -9,
+ WLONGVARCHAR = -10,
+
+ // Extended data types (sqlext.h)
+ INTERVAL = 10, // V3 Only
+ TIME = 10,
+ TIMESTAMP = 11,
+ LONGVARCHAR = -1,
+ BINARY = -2,
+ VARBINARY = -3,
+ LONGVARBINARY = -4,
+ BIGINT = -5,
+ TINYINT = -6,
+ BIT = -7,
+ GUID = -11, // V3 Only
+
+ // One-parameter shortcuts for date/time data types.
+ TYPE_DATE = 91,
+ TYPE_TIME = 92,
+ TYPE_TIMESTAMP = 93,
+
+ // SQL Server Types -150 to -159 (sqlncli.h)
+ SS_VARIANT = -150,
+ SS_UDT = -151,
+ SS_XML = -152,
+ SS_TABLE = -153,
+ SS_TIME2 = -154,
+ SS_TIMESTAMPOFFSET = -155
+ ],
+
+ //SQL_ALL_TYPES = 0,
+ //static public readonly IntPtr SQL_HANDLE_NULL = IntPtr.Zero;
+
+ SQL_LENGTH =
+ [
+ SQL_IGNORE = -6,
+ SQL_DEFAULT_PARAM = -5,
+ SQL_NO_TOTAL = -4,
+ SQL_NTS = -3,
+ SQL_DATA_AT_EXEC = -2,
+ SQL_NULL_DATA = -1
+ ],
+
+ SQL_DEFAULT_PARAM = -5,
+
+ // column ordinals for SQLProcedureColumns result set
+ // this column ordinals are not defined in any c/c++ header but in the ODBC Programmer's Reference under SQLProcedureColumns
+ //
+ COLUMN_NAME = 4,
+ COLUMN_TYPE = 5,
+ DATA_TYPE = 6,
+ COLUMN_SIZE = 8,
+ DECIMAL_DIGITS = 10,
+ NUM_PREC_RADIX = 11,
+
+ SQL_ATTR =
+ [
+ ODBC_VERSION = 200,
+ CONNECTION_POOLING = 201,
+ AUTOCOMMIT = 102,
+ TXN_ISOLATION = 108,
+ CURRENT_CATALOG = 109,
+ LOGIN_TIMEOUT = 103,
+ QUERY_TIMEOUT = 0,
+ CONNECTION_DEAD = 1209,
+
+ SQL_COPT_SS_BASE = 1200,
+ SQL_COPT_SS_ENLIST_IN_DTC = (1200 + 7),
+ SQL_COPT_SS_TXN_ISOLATION = (1200 + 27),
+
+ MAX_LENGTH = 3,
+ ROW_BIND_TYPE = 5,
+ CURSOR_TYPE = 6,
+ RETRIEVE_DATA = 11,
+ ROW_STATUS_PTR = 25,
+ ROWS_FETCHED_PTR = 26,
+ ROW_ARRAY_SIZE = 27,
+
+ // ODBC 3.0
+ APP_ROW_DESC = 10010,
+ APP_PARAM_DESC = 10011,
+ IMP_ROW_DESC = 10012,
+ IMP_PARAM_DESC = 10013,
+ METADATA_ID = 10014,
+
+ // ODBC 4.0
+ PRIVATE_DRIVER_LOCATION = 204
+ ],
+
+ SQL_RD =
+ [
+ OFF = 0,
+ ON = 1
+ ],
+
+ SQL_GD =
+ [
+ //None = 0,
+ ANY_COLUMN = 1,
+ ANY_ORDER = 2,
+ BLOCK = 4,
+ BOUND = 8,
+ OUTPUT_PARAMS = 16
+ ],
+
+ //SQLGetInfo
+/*
+ SQL_INFO =
+ [
+ SQL_ACTIVE_CONNECTIONS = 0,
+ SQL_MAX_DRIVER_CONNECTIONS = 0,
+ SQL_MAX_CONCURRENT_ACTIVITIES = 1,
+ SQL_ACTIVE_STATEMENTS = 1,
+ SQL_DATA_SOURCE_NAME = 2,
+ SQL_DRIVER_HDBC,
+ SQL_DRIVER_HENV,
+ SQL_DRIVER_HSTMT,
+ SQL_DRIVER_NAME,
+ SQL_DRIVER_VER,
+ SQL_FETCH_DIRECTION,
+ SQL_ODBC_API_CONFORMANCE,
+ SQL_ODBC_VER,
+ SQL_ROW_UPDATES,
+ SQL_ODBC_SAG_CLI_CONFORMANCE,
+ SQL_SERVER_NAME,
+ SQL_SEARCH_PATTERN_ESCAPE,
+ SQL_ODBC_SQL_CONFORMANCE,
+
+ SQL_DATABASE_NAME,
+ SQL_DBMS_NAME,
+ SQL_DBMS_VER,
+
+ SQL_ACCESSIBLE_TABLES,
+ SQL_ACCESSIBLE_PROCEDURES,
+ SQL_PROCEDURES,
+ SQL_CONCAT_NULL_BEHAVIOR,
+ SQL_CURSOR_COMMIT_BEHAVIOR,
+ SQL_CURSOR_ROLLBACK_BEHAVIOR,
+ SQL_DATA_SOURCE_READ_ONLY,
+ SQL_DEFAULT_TXN_ISOLATION,
+ SQL_EXPRESSIONS_IN_ORDERBY,
+ SQL_IDENTIFIER_CASE,
+ SQL_IDENTIFIER_QUOTE_CHAR,
+ SQL_MAX_COLUMN_NAME_LEN,
+ SQL_MAX_CURSOR_NAME_LEN,
+ SQL_MAX_OWNER_NAME_LEN,
+ SQL_MAX_SCHEMA_NAME_LEN = 32,
+ SQL_MAX_PROCEDURE_NAME_LEN,
+ SQL_MAX_QUALIFIER_NAME_LEN,
+ SQL_MAX_CATALOG_NAME_LEN = 34,
+ SQL_MAX_TABLE_NAME_LEN,
+ SQL_MULT_RESULT_SETS,
+ SQL_MULTIPLE_ACTIVE_TXN,
+ SQL_OUTER_JOINS,
+ SQL_SCHEMA_TERM,
+ SQL_PROCEDURE_TERM,
+ SQL_CATALOG_NAME_SEPARATOR,
+ SQL_CATALOG_TERM,
+ SQL_SCROLL_CONCURRENCY,
+ SQL_SCROLL_OPTIONS,
+ SQL_TABLE_TERM,
+ SQL_TXN_CAPABLE,
+ SQL_USER_NAME,
+
+ SQL_CONVERT_FUNCTIONS,
+ SQL_NUMERIC_FUNCTIONS,
+ SQL_STRING_FUNCTIONS,
+ SQL_SYSTEM_FUNCTIONS,
+ SQL_TIMEDATE_FUNCTIONS,
+
+ SQL_CONVERT_BIGINT,
+ SQL_CONVERT_BINARY,
+ SQL_CONVERT_BIT,
+ SQL_CONVERT_CHAR,
+ SQL_CONVERT_DATE,
+ SQL_CONVERT_DECIMAL,
+ SQL_CONVERT_DOUBLE,
+ SQL_CONVERT_FLOAT,
+ SQL_CONVERT_INTEGER,
+ SQL_CONVERT_LONGVARCHAR,
+ SQL_CONVERT_NUMERIC,
+ SQL_CONVERT_REAL,
+ SQL_CONVERT_SMALLINT,
+ SQL_CONVERT_TIME,
+ SQL_CONVERT_TIMESTAMP,
+ SQL_CONVERT_TINYINT,
+ SQL_CONVERT_VARBINARY,
+ SQL_CONVERT_VARCHAR,
+ SQL_CONVERT_LONGVARBINARY,
+
+ SQL_TXN_ISOLATION_OPTION,
+ SQL_ODBC_SQL_OPT_IEF,
+ SQL_INTEGRITY = 73,
+ SQL_CORRELATION_NAME,
+ SQL_NON_NULLABLE_COLUMNS,
+ SQL_DRIVER_HLIB,
+ SQL_DRIVER_ODBC_VER,
+ SQL_LOCK_TYPES,
+ SQL_POS_OPERATIONS,
+ SQL_POSITIONED_STATEMENTS,
+ SQL_GETDATA_EXTENSIONS,
+ SQL_BOOKMARK_PERSISTENCE,
+ SQL_STATIC_SENSITIVITY,
+ SQL_FILE_USAGE,
+ SQL_NULL_COLLATION,
+ SQL_ALTER_TABLE,
+ SQL_COLUMN_ALIAS,
+ SQL_GROUP_BY,
+ SQL_KEYWORDS,
+ SQL_ORDER_BY_COLUMNS_IN_SELECT,
+ SQL_SCHEMA_USAGE,
+ SQL_CATALOG_USAGE,
+ SQL_QUOTED_IDENTIFIER_CASE,
+ SQL_SPECIAL_CHARACTERS,
+ SQL_SUBQUERIES,
+ SQL_UNION_STATEMENT,
+ SQL_MAX_COLUMNS_IN_GROUP_BY,
+ SQL_MAX_COLUMNS_IN_INDEX,
+ SQL_MAX_COLUMNS_IN_ORDER_BY,
+ SQL_MAX_COLUMNS_IN_SELECT,
+ SQL_MAX_COLUMNS_IN_TABLE,
+ SQL_MAX_INDEX_SIZE,
+ SQL_MAX_ROW_SIZE_INCLUDES_LONG,
+ SQL_MAX_ROW_SIZE,
+ SQL_MAX_STATEMENT_LEN,
+ SQL_MAX_TABLES_IN_SELECT,
+ SQL_MAX_USER_NAME_LEN,
+ SQL_MAX_CHAR_LITERAL_LEN,
+ SQL_TIMEDATE_ADD_INTERVALS,
+ SQL_TIMEDATE_DIFF_INTERVALS,
+ SQL_NEED_LONG_DATA_LEN,
+ SQL_MAX_BINARY_LITERAL_LEN,
+ SQL_LIKE_ESCAPE_CLAUSE,
+ SQL_CATALOG_LOCATION,
+ SQL_OJ_CAPABILITIES,
+
+ SQL_ACTIVE_ENVIRONMENTS,
+ SQL_ALTER_DOMAIN,
+ SQL_SQL_CONFORMANCE,
+ SQL_DATETIME_LITERALS,
+ SQL_BATCH_ROW_COUNT,
+ SQL_BATCH_SUPPORT,
+ SQL_CONVERT_WCHAR,
+ SQL_CONVERT_INTERVAL_DAY_TIME,
+ SQL_CONVERT_INTERVAL_YEAR_MONTH,
+ SQL_CONVERT_WLONGVARCHAR,
+ SQL_CONVERT_WVARCHAR,
+ SQL_CREATE_ASSERTION,
+ SQL_CREATE_CHARACTER_SET,
+ SQL_CREATE_COLLATION,
+ SQL_CREATE_DOMAIN,
+ SQL_CREATE_SCHEMA,
+ SQL_CREATE_TABLE,
+ SQL_CREATE_TRANSLATION,
+ SQL_CREATE_VIEW,
+ SQL_DRIVER_HDESC,
+ SQL_DROP_ASSERTION,
+ SQL_DROP_CHARACTER_SET,
+ SQL_DROP_COLLATION,
+ SQL_DROP_DOMAIN,
+ SQL_DROP_SCHEMA,
+ SQL_DROP_TABLE,
+ SQL_DROP_TRANSLATION,
+ SQL_DROP_VIEW,
+ SQL_DYNAMIC_CURSOR_ATTRIBUTES1,
+ SQL_DYNAMIC_CURSOR_ATTRIBUTES2,
+ SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1,
+ SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2,
+ SQL_INDEX_KEYWORDS,
+ SQL_INFO_SCHEMA_VIEWS,
+ SQL_KEYSET_CURSOR_ATTRIBUTES1,
+ SQL_KEYSET_CURSOR_ATTRIBUTES2,
+ SQL_ODBC_INTERFACE_CONFORMANCE,
+ SQL_PARAM_ARRAY_ROW_COUNTS,
+ SQL_PARAM_ARRAY_SELECTS,
+ SQL_SQL92_DATETIME_FUNCTIONS,
+ SQL_SQL92_FOREIGN_KEY_DELETE_RULE,
+ SQL_SQL92_FOREIGN_KEY_UPDATE_RULE,
+ SQL_SQL92_GRANT,
+ SQL_SQL92_NUMERIC_VALUE_FUNCTIONS,
+ SQL_SQL92_PREDICATES,
+ SQL_SQL92_RELATIONAL_JOIN_OPERATORS,
+ SQL_SQL92_REVOKE,
+ SQL_SQL92_ROW_VALUE_CONSTRUCTOR,
+ SQL_SQL92_STRING_FUNCTIONS,
+ SQL_SQL92_VALUE_EXPRESSIONS,
+ SQL_STANDARD_CLI_CONFORMANCE,
+ SQL_STATIC_CURSOR_ATTRIBUTES1,
+ SQL_STATIC_CURSOR_ATTRIBUTES2,
+ SQL_AGGREGATE_FUNCTIONS,
+ SQL_DDL_INDEX,
+ SQL_DM_VER,
+ SQL_INSERT_STATEMENT,
+ SQL_CONVERT_GUID,
+
+ SQL_XOPEN_CLI_YEAR = 10000,
+ SQL_CURSOR_SENSITIVITY,
+ SQL_DESCRIBE_PARAMETER,
+ SQL_CATALOG_NAME,
+ SQL_COLLATION_SEQ,
+ SQL_MAX_IDENTIFIER_LEN,
+ SQL_ASYNC_MODE = 10021,
+ SQL_MAX_ASYNC_CONCURRENT_STATEMENTS,
+
+ SQL_DTC_TRANSITION_COST = 1750,
+ ],
+*/
+ SQL_OAC =
+ [
+ SQL_OAC_None = 0x0000,
+ SQL_OAC_LEVEL1 = 0x0001,
+ SQL_OAC_LEVEL2 = 0x0002
+ ],
+
+ SQL_OSC =
+ [
+ SQL_OSC_MINIMUM = 0x0000,
+ SQL_OSC_CORE = 0x0001,
+ SQL_OSC_EXTENDED = 0x0002
+ ],
+
+ SQL_SCC =
+ [
+ SQL_SCC_XOPEN_CLI_VERSION1 = 0x00000001,
+ SQL_SCC_ISO92_CLI = 0x00000002
+ ],
+
+ SQL_SVE =
+ [
+ SQL_SVE_CASE = 0x00000001,
+ SQL_SVE_CAST = 0x00000002,
+ SQL_SVE_COALESCE = 0x00000004,
+ SQL_SVE_NULLIF = 0x00000008
+ ],
+
+ SQL_SSF =
+ [
+ SQL_SSF_CONVERT = 0x00000001,
+ SQL_SSF_LOWER = 0x00000002,
+ SQL_SSF_UPPER = 0x00000004,
+ SQL_SSF_SUBSTRING = 0x00000008,
+ SQL_SSF_TRANSLATE = 0x00000010,
+ SQL_SSF_TRIM_BOTH = 0x00000020,
+ SQL_SSF_TRIM_LEADING = 0x00000040,
+ SQL_SSF_TRIM_TRAILING = 0x00000080
+ ],
+
+ SQL_SP =
+ [
+ //None = 0,
+
+ SQL_SP_EXISTS = 0x00000001,
+ SQL_SP_ISNOTNULL = 0x00000002,
+ SQL_SP_ISNULL = 0x00000004,
+ SQL_SP_MATCH_FULL = 0x00000008,
+ SQL_SP_MATCH_PARTIAL = 0x00000010,
+ SQL_SP_MATCH_UNIQUE_FULL = 0x00000020,
+ SQL_SP_MATCH_UNIQUE_PARTIAL = 0x00000040,
+ SQL_SP_OVERLAPS = 0x00000080,
+ SQL_SP_UNIQUE = 0x00000100,
+ SQL_SP_LIKE = 0x00000200,
+ SQL_SP_IN = 0x00000400,
+ SQL_SP_BETWEEN = 0x00000800,
+ SQL_SP_COMPARISON = 0x00001000,
+ SQL_SP_QUANTIFIED_COMPARISON = 0x00002000,
+
+ All = 0x0000FFFF
+ ],
+
+ SQL_OIC =
+ [
+ SQL_OIC_CORE = 1,
+ SQL_OIC_LEVEL1 = 2,
+ SQL_OIC_LEVEL2 = 3
+ ],
+
+ SQL_USAGE =
+ [
+ SQL_U_DML_STATEMENTS = 0x00000001,
+ SQL_U_PROCEDURE_INVOCATION = 0x00000002,
+ SQL_U_TABLE_DEFINITION = 0x00000004,
+ SQL_U_INDEX_DEFINITION = 0x00000008,
+ SQL_U_PRIVILEGE_DEFINITION = 0x00000010
+ ],
+
+ SQL_GB =
+ [
+
+ SQL_GB_NOT_SUPPORTED = 0,
+ SQL_GB_GROUP_BY_EQUALS_SELECT = 1,
+ SQL_GB_GROUP_BY_CONTAINS_SELECT = 2,
+ SQL_GB_NO_RELATION = 3,
+ SQL_GB_COLLATE = 4
+ ],
+
+ SQL_NC =
+ [
+ SQL_NC_END = 0,
+ SQL_NC_HIGH = 1,
+ SQL_NC_LOW = 2,
+ SQL_NC_START = 3
+ ],
+
+ SQL_CN =
+ [
+ SQL_CN_None = 0,
+ SQL_CN_DIFFERENT = 1,
+ SQL_CN_ANY = 2
+ ],
+
+ SQL_NNC =
+ [
+ SQL_NNC_NULL = 0,
+ SQL_NNC_NON_NULL = 1
+ ],
+
+ SQL_CB =
+ [
+ SQL_CB_NULL = 0,
+ SQL_CB_NON_NULL = 1
+ ],
+
+ SQL_FD_FETCH =
+ [
+ SQL_FD_FETCH_NEXT = 0x00000001,
+ SQL_FD_FETCH_FIRST = 0x00000002,
+ SQL_FD_FETCH_LAST = 0x00000004,
+ SQL_FD_FETCH_PRIOR = 0x00000008,
+ SQL_FD_FETCH_ABSOLUTE = 0x00000010,
+ SQL_FD_FETCH_RELATIVE = 0x00000020,
+ SQL_FD_FETCH_BOOKMARK = 0x00000080
+ ],
+
+ SQL_SQ =
+ [
+ SQL_SQ_COMPARISON = 0x00000001,
+ SQL_SQ_EXISTS = 0x00000002,
+ SQL_SQ_IN = 0x00000004,
+ SQL_SQ_QUANTIFIED = 0x00000008,
+ SQL_SQ_CORRELATED_SUBQUERIES = 0x00000010
+ ],
+
+ SQL_U =
+ [
+ SQL_U_UNION = 0x00000001,
+ SQL_U_UNION_ALL = 0x00000002
+ ],
+
+ SQL_BP =
+ [
+ SQL_BP_CLOSE = 0x00000001,
+ SQL_BP_DELETE = 0x00000002,
+ SQL_BP_DROP = 0x00000004,
+ SQL_BP_TRANSACTION = 0x00000008,
+ SQL_BP_UPDATE = 0x00000010,
+ SQL_BP_OTHER_HSTMT = 0x00000020,
+ SQL_BP_SCROLL = 0x00000040
+ ],
+
+ SQL_QL =
+ [
+ SQL_QL_START = 0x0001,
+ SQL_QL_END = 0x0002
+ ],
+
+ SQL_OJ =
+ [
+ SQL_OJ_LEFT = 0x00000001,
+ SQL_OJ_RIGHT = 0x00000002,
+ SQL_OJ_FULL = 0x00000004,
+ SQL_OJ_NESTED = 0x00000008,
+ SQL_OJ_NOT_ORDERED = 0x00000010,
+ SQL_OJ_INNER = 0x00000020,
+ SQL_OJ_ALL_COMPARISON_OPS = 0x00000040
+ ],
+
+ SQL_FN_CVT =
+ [
+ //None = 0,
+
+ SQL_FN_CVT_CONVERT = 0x00000001,
+ SQL_FN_CVT_CAST = 0x00000002
+ ],
+
+ SQL_FN_NUM =
+ [
+ //None = 0,
+
+ SQL_FN_NUM_ABS = 0x00000001,
+ SQL_FN_NUM_ACOS = 0x00000002,
+ SQL_FN_NUM_ASIN = 0x00000004,
+ SQL_FN_NUM_ATAN = 0x00000008,
+ SQL_FN_NUM_ATAN2 = 0x00000010,
+ SQL_FN_NUM_CEILING = 0x00000020,
+ SQL_FN_NUM_COS = 0x00000040,
+ SQL_FN_NUM_COT = 0x00000080,
+ SQL_FN_NUM_EXP = 0x00000100,
+ SQL_FN_NUM_FLOOR = 0x00000200,
+ SQL_FN_NUM_LOG = 0x00000400,
+ SQL_FN_NUM_MOD = 0x00000800,
+ SQL_FN_NUM_SIGN = 0x00001000,
+ SQL_FN_NUM_SIN = 0x00002000,
+ SQL_FN_NUM_SQRT = 0x00004000,
+ SQL_FN_NUM_TAN = 0x00008000,
+ SQL_FN_NUM_PI = 0x00010000,
+ SQL_FN_NUM_RAND = 0x00020000,
+ SQL_FN_NUM_DEGREES = 0x00040000,
+ SQL_FN_NUM_LOG10 = 0x00080000,
+ SQL_FN_NUM_POWER = 0x00100000,
+ SQL_FN_NUM_RADIANS = 0x00200000,
+ SQL_FN_NUM_ROUND = 0x00400000,
+ SQL_FN_NUM_TRUNCATE = 0x00800000
+ ],
+
+ SQL_SNVF =
+ [
+ SQL_SNVF_BIT_LENGTH = 0x00000001,
+ SQL_SNVF_CHAR_LENGTH = 0x00000002,
+ SQL_SNVF_CHARACTER_LENGTH = 0x00000004,
+ SQL_SNVF_EXTRACT = 0x00000008,
+ SQL_SNVF_OCTET_LENGTH = 0x00000010,
+ SQL_SNVF_POSITION = 0x00000020
+ ],
+
+ SQL_FN_STR =
+ [
+ //None = 0,
+
+ SQL_FN_STR_CONCAT = 0x00000001,
+ SQL_FN_STR_INSERT = 0x00000002,
+ SQL_FN_STR_LEFT = 0x00000004,
+ SQL_FN_STR_LTRIM = 0x00000008,
+ SQL_FN_STR_LENGTH = 0x00000010,
+ SQL_FN_STR_LOCATE = 0x00000020,
+ SQL_FN_STR_LCASE = 0x00000040,
+ SQL_FN_STR_REPEAT = 0x00000080,
+ SQL_FN_STR_REPLACE = 0x00000100,
+ SQL_FN_STR_RIGHT = 0x00000200,
+ SQL_FN_STR_RTRIM = 0x00000400,
+ SQL_FN_STR_SUBSTRING = 0x00000800,
+ SQL_FN_STR_UCASE = 0x00001000,
+ SQL_FN_STR_ASCII = 0x00002000,
+ SQL_FN_STR_CHAR = 0x00004000,
+ SQL_FN_STR_DIFFERENCE = 0x00008000,
+ SQL_FN_STR_LOCATE_2 = 0x00010000,
+ SQL_FN_STR_SOUNDEX = 0x00020000,
+ SQL_FN_STR_SPACE = 0x00040000,
+ SQL_FN_STR_BIT_LENGTH = 0x00080000,
+ SQL_FN_STR_CHAR_LENGTH = 0x00100000,
+ SQL_FN_STR_CHARACTER_LENGTH = 0x00200000,
+ SQL_FN_STR_OCTET_LENGTH = 0x00400000,
+ SQL_FN_STR_POSITION = 0x00800000
+ ],
+
+ SQL_FN_SYSTEM =
+ [
+ //None = 0,
+
+ SQL_FN_SYS_USERNAME = 0x00000001,
+ SQL_FN_SYS_DBNAME = 0x00000002,
+ SQL_FN_SYS_IFNULL = 0x00000004
+ ],
+
+ SQL_FN_TD =
+ [
+ //None = 0,
+
+ SQL_FN_TD_NOW = 0x00000001,
+ SQL_FN_TD_CURDATE = 0x00000002,
+ SQL_FN_TD_DAYOFMONTH = 0x00000004,
+ SQL_FN_TD_DAYOFWEEK = 0x00000008,
+ SQL_FN_TD_DAYOFYEAR = 0x00000010,
+ SQL_FN_TD_MONTH = 0x00000020,
+ SQL_FN_TD_QUARTER = 0x00000040,
+ SQL_FN_TD_WEEK = 0x00000080,
+ SQL_FN_TD_YEAR = 0x00000100,
+ SQL_FN_TD_CURTIME = 0x00000200,
+ SQL_FN_TD_HOUR = 0x00000400,
+ SQL_FN_TD_MINUTE = 0x00000800,
+ SQL_FN_TD_SECOND = 0x00001000,
+ SQL_FN_TD_TIMESTAMPADD = 0x00002000,
+ SQL_FN_TD_TIMESTAMPDIFF = 0x00004000,
+ SQL_FN_TD_DAYNAME = 0x00008000,
+ SQL_FN_TD_MONTHNAME = 0x00010000,
+ SQL_FN_TD_CURRENT_DATE = 0x00020000,
+ SQL_FN_TD_CURRENT_TIME = 0x00040000,
+ SQL_FN_TD_CURRENT_TIMESTAMP = 0x00080000,
+ SQL_FN_TD_EXTRACT = 0x00100000
+ ],
+
+ SQL_SDF =
+ [
+ SQL_SDF_CURRENT_DATE = 0x00000001,
+ SQL_SDF_CURRENT_TIME = 0x00000002,
+ SQL_SDF_CURRENT_TIMESTAMP = 0x00000004
+ ],
+
+ SQL_TSI =
+ [
+ //None = 0,
+
+ SQL_TSI_FRAC_SECOND = 0x00000001,
+ SQL_TSI_SECOND = 0x00000002,
+ SQL_TSI_MINUTE = 0x00000004,
+ SQL_TSI_HOUR = 0x00000008,
+ SQL_TSI_DAY = 0x00000010,
+ SQL_TSI_WEEK = 0x00000020,
+ SQL_TSI_MONTH = 0x00000040,
+ SQL_TSI_QUARTER = 0x00000080,
+ SQL_TSI_YEAR = 0x00000100
+ ],
+
+ SQL_AF =
+ [
+ //None = 0,
+
+ SQL_AF_AVG = 0x00000001,
+ SQL_AF_COUNT = 0x00000002,
+ SQL_AF_MAX = 0x00000004,
+ SQL_AF_MIN = 0x00000008,
+ SQL_AF_SUM = 0x00000010,
+ SQL_AF_DISTINCT = 0x00000020,
+ SQL_AF_ALL = 0x00000040,
+
+ All = 0xFF
+ ],
+
+ SQL_SC =
+ [
+ //None = 0,
+
+ SQL_SC_SQL92_ENTRY = 0x00000001,
+ SQL_SC_FIPS127_2_TRANSITIONAL = 0x00000002,
+ SQL_SC_SQL92_INTERMEDIATE = 0x00000004,
+ SQL_SC_SQL92_FULL = 0x00000008
+ ],
+
+ SQL_DL_SQL92 =
+ [
+ SQL_DL_SQL92_DATE = 0x00000001,
+ SQL_DL_SQL92_TIME = 0x00000002,
+ SQL_DL_SQL92_TIMESTAMP = 0x00000004,
+ SQL_DL_SQL92_INTERVAL_YEAR = 0x00000008,
+ SQL_DL_SQL92_INTERVAL_MONTH = 0x00000010,
+ SQL_DL_SQL92_INTERVAL_DAY = 0x00000020,
+ SQL_DL_SQL92_INTERVAL_HOUR = 0x00000040,
+ SQL_DL_SQL92_INTERVAL_MINUTE = 0x00000080,
+ SQL_DL_SQL92_INTERVAL_SECOND = 0x00000100,
+ SQL_DL_SQL92_INTERVAL_YEAR_TO_MONTH = 0x00000200,
+ SQL_DL_SQL92_INTERVAL_DAY_TO_HOUR = 0x00000400,
+ SQL_DL_SQL92_INTERVAL_DAY_TO_MINUTE = 0x00000800,
+ SQL_DL_SQL92_INTERVAL_DAY_TO_SECOND = 0x00001000,
+ SQL_DL_SQL92_INTERVAL_HOUR_TO_MINUTE = 0x00002000,
+ SQL_DL_SQL92_INTERVAL_HOUR_TO_SECOND = 0x00004000,
+ SQL_DL_SQL92_INTERVAL_MINUTE_TO_SECOND = 0x00008000
+ ],
+
+ SQL_IK =
+ [
+ SQL_IK_NONE = 0x00000000,
+ SQL_IK_ASC = 0x00000001,
+ SQL_IK_DESC = 0x00000002,
+ SQL_IK_ALL = 0x00000003 //SQL_IK_ASC | SQL_IK_DESC
+ ],
+
+ SQL_ISV =
+ [
+ SQL_ISV_ASSERTIONS = 0x00000001,
+ SQL_ISV_CHARACTER_SETS = 0x00000002,
+ SQL_ISV_CHECK_CONSTRAINTS = 0x00000004,
+ SQL_ISV_COLLATIONS = 0x00000008,
+ SQL_ISV_COLUMN_DOMAIN_USAGE = 0x00000010,
+ SQL_ISV_COLUMN_PRIVILEGES = 0x00000020,
+ SQL_ISV_COLUMNS = 0x00000040,
+ SQL_ISV_CONSTRAINT_COLUMN_USAGE = 0x00000080,
+ SQL_ISV_CONSTRAINT_TABLE_USAGE = 0x00000100,
+ SQL_ISV_DOMAIN_CONSTRAINTS = 0x00000200,
+ SQL_ISV_DOMAINS = 0x00000400,
+ SQL_ISV_KEY_COLUMN_USAGE = 0x00000800,
+ SQL_ISV_REFERENTIAL_CONSTRAINTS = 0x00001000,
+ SQL_ISV_SCHEMATA = 0x00002000,
+ SQL_ISV_SQL_LANGUAGES = 0x00004000,
+ SQL_ISV_TABLE_CONSTRAINTS = 0x00008000,
+ SQL_ISV_TABLE_PRIVILEGES = 0x00010000,
+ SQL_ISV_TABLES = 0x00020000,
+ SQL_ISV_TRANSLATIONS = 0x00040000,
+ SQL_ISV_USAGE_PRIVILEGES = 0x00080000,
+ SQL_ISV_VIEW_COLUMN_USAGE = 0x00100000,
+ SQL_ISV_VIEW_TABLE_USAGE = 0x00200000,
+ SQL_ISV_VIEWS = 0x00400000
+ ],
+
+ SQL_SRJO =
+ [
+ //None = 0,
+
+ SQL_SRJO_CORRESPONDING_CLAUSE = 0x00000001,
+ SQL_SRJO_CROSS_JOIN = 0x00000002,
+ SQL_SRJO_EXCEPT_JOIN = 0x00000004,
+ SQL_SRJO_FULL_OUTER_JOIN = 0x00000008,
+ SQL_SRJO_INNER_JOIN = 0x00000010,
+ SQL_SRJO_INTERSECT_JOIN = 0x00000020,
+ SQL_SRJO_LEFT_OUTER_JOIN = 0x00000040,
+ SQL_SRJO_NATURAL_JOIN = 0x00000080,
+ SQL_SRJO_RIGHT_OUTER_JOIN = 0x00000100,
+ SQL_SRJO_UNION_JOIN = 0x00000200
+ ],
+
+ SQL_SRVC =
+ [
+ SQL_SRVC_VALUE_EXPRESSION = 0x00000001,
+ SQL_SRVC_NULL = 0x00000002,
+ SQL_SRVC_DEFAULT = 0x00000004,
+ SQL_SRVC_ROW_SUBQUERY = 0x00000008
+ ],
+
+ //public static readonly int SQL_OV_ODBC3 = 3;
+ //public const Int32 SQL_NTS = -3; //flags for null-terminated string
+
+ //Pooling
+ SQL_CP =
+ [
+ OFF = 0,
+ ONE_PER_DRIVER = 1,
+ ONE_PER_HENV = 2
+ ],
+
+/*
+ public const Int32 SQL_CD_TRUE = 1;
+ public const Int32 SQL_CD_FALSE = 0;
+
+ public const Int32 SQL_DTC_DONE = 0;
+ public const Int32 SQL_IS_POINTER = -4;
+ public const Int32 SQL_IS_PTR = 1;
+*/
+ SQL_DRIVER =
+ [
+ NOPROMPT = 0,
+ COMPLETE = 1,
+ PROMPT = 2,
+ COMPLETE_REQUIRED = 3
+ ],
+
+ // Column set for SQLPrimaryKeys
+ SQL_PRIMARYKEYS =
+ [
+ /*
+ CATALOGNAME = 1, // TABLE_CAT
+ SCHEMANAME = 2, // TABLE_SCHEM
+ TABLENAME = 3, // TABLE_NAME
+ */
+ COLUMNNAME = 4 // COLUMN_NAME
+ /*
+ KEY_SEQ = 5, // KEY_SEQ
+ PKNAME = 6, // PK_NAME
+ */
+ ],
+
+ // Column set for SQLStatistics
+ SQL_STATISTICS =
+ [
+ /*
+ CATALOGNAME = 1, // TABLE_CAT
+ SCHEMANAME = 2, // TABLE_SCHEM
+ TABLENAME = 3, // TABLE_NAME
+ NONUNIQUE = 4, // NON_UNIQUE
+ INDEXQUALIFIER = 5, // INDEX_QUALIFIER
+ */
+ INDEXNAME = 6, // INDEX_NAME
+ /*
+ TYPE = 7, // TYPE
+ */
+ ORDINAL_POSITION = 8, // ORDINAL_POSITION
+ COLUMN_NAME = 9 // COLUMN_NAME
+ /*
+ ASC_OR_DESC = 10, // ASC_OR_DESC
+ CARDINALITY = 11, // CARDINALITY
+ PAGES = 12, // PAGES
+ FILTER_CONDITION = 13, // FILTER_CONDITION
+ */
+ ],
+
+ // Column set for SQLSpecialColumns
+ SQL_SPECIALCOLUMNSET =
+ [
+ /*
+ SCOPE = 1, // SCOPE
+ */
+ COLUMN_NAME = 2 // COLUMN_NAME
+ /*
+ DATA_TYPE = 3, // DATA_TYPE
+ TYPE_NAME = 4, // TYPE_NAME
+ COLUMN_SIZE = 5, // COLUMN_SIZE
+ BUFFER_LENGTH = 6, // BUFFER_LENGTH
+ DECIMAL_DIGITS = 7, // DECIMAL_DIGITS
+ PSEUDO_COLUMN = 8, // PSEUDO_COLUMN
+ */
+ ],
+
+ SQL_DIAG =
+ [
+ CURSOR_ROW_COUNT= -1249,
+ ROW_NUMBER = -1248,
+ COLUMN_NUMBER = -1247,
+ RETURNCODE = 1,
+ NUMBER = 2,
+ ROW_COUNT = 3,
+ SQLSTATE = 4,
+ NATIVE = 5,
+ MESSAGE_TEXT = 6,
+ DYNAMIC_FUNCTION = 7,
+ CLASS_ORIGIN = 8,
+ SUBCLASS_ORIGIN = 9,
+ CONNECTION_NAME = 10,
+ SERVER_NAME = 11,
+ DYNAMIC_FUNCTION_CODE = 12
+ ],
+
+ SQL_SU =
+ [
+ SQL_SU_DML_STATEMENTS = 0x00000001,
+ SQL_SU_PROCEDURE_INVOCATION = 0x00000002,
+ SQL_SU_TABLE_DEFINITION = 0x00000004,
+ SQL_SU_INDEX_DEFINITION = 0x00000008,
+ SQL_SU_PRIVILEGE_DEFINITION = 0x00000010
+ ]
+]
diff --git a/sql-odbc/src/PowerBIConnector/OdfeSqlOdbcPBIConnector.mproj b/sql-odbc/src/PowerBIConnector/OdfeSqlOdbcPBIConnector.mproj
index 0987401eb4..543b5652c8 100644
--- a/sql-odbc/src/PowerBIConnector/OdfeSqlOdbcPBIConnector.mproj
+++ b/sql-odbc/src/PowerBIConnector/OdfeSqlOdbcPBIConnector.mproj
@@ -66,6 +66,12 @@
Code
+
+ Content
+
+
+ Content
+
Code
diff --git a/sql-odbc/src/PowerBIConnector/OdfeSqlOdbcPBIConnector.pq b/sql-odbc/src/PowerBIConnector/OdfeSqlOdbcPBIConnector.pq
index 6b9abdba5b..f1af5f74b6 100644
--- a/sql-odbc/src/PowerBIConnector/OdfeSqlOdbcPBIConnector.pq
+++ b/sql-odbc/src/PowerBIConnector/OdfeSqlOdbcPBIConnector.pq
@@ -1,6 +1,12 @@
-// This file contains your Data Connector logic
+// This file contains Data Connector logic
section OdfeSqlOdbcPBIConnector;
+// When set to true, additional trace information will be written out to the User log.
+// This should be set to false before release. Tracing is done through a call to
+// Diagnostics.LogValue(). When EnableTraceOutput is set to false, the call becomes a
+// no-op and simply returns the original value.
+EnableTraceOutput = true;
+
[DataSource.Kind="OdfeSqlOdbcPBIConnector", Publish="OdfeSqlOdbcPBIConnector.Publish"]
shared OdfeSqlOdbcPBIConnector.Contents = Value.ReplaceType(OdfeSqlOdbcPBIConnectorImpl, OdfeSqlOdbcPBIConnectorType);
@@ -8,12 +14,12 @@ shared OdfeSqlOdbcPBIConnector.Contents = Value.ReplaceType(OdfeSqlOdbcPBIConnec
OdfeSqlOdbcPBIConnectorType = type function (
Host as (type text meta [
Documentation.FieldCaption = "Host",
- Documentation.FieldDescription = "The hostname of the Open Distro For Elasticsearc server.",
+ Documentation.FieldDescription = "The hostname of the Open Distro For Elasticsearch server.",
Documentation.SampleValues = { "localhost" }
]),
- Port as (type number meta [
+ optional Port as (type number meta [
Documentation.FieldCaption = "Port",
- Documentation.FieldDescription = "The port the Open Distro For Elasticsearc server is running on.",
+ Documentation.FieldDescription = "The port of the Open Distro For Elasticsearch server is running on.",
Documentation.SampleValues = { 9200 }
])
)
@@ -21,22 +27,177 @@ OdfeSqlOdbcPBIConnectorType = type function (
Documentation.Name = "Open Distro For Elasticsearch"
];
-OdfeSqlOdbcPBIConnectorImpl = (Host as text, Port as number) as table =>
+OdfeSqlOdbcPBIConnectorImpl = (Host as text, optional Port as number) as table =>
let
+ Credential = Extension.CurrentCredential(),
+ AuthenticationMode = Credential[AuthenticationKind],
+
+ // Sets connection string properties for authentication.
+ CredentialConnectionString =
+ if AuthenticationMode = "UsernamePassword" then
+ [
+ Auth = "BASIC",
+ UID = Credential[Username],
+ PWD = Credential[Password]
+ ]
+ else if AuthenticationMode = "Key" then
+ [
+ Auth = "AWS_SIGV4",
+ Region = Credential[Key]
+ ]
+ else
+ [
+ Auth = "NONE"
+ ],
+
+ // Sets connection string properties for encrypted connections.
+ EncryptedConnectionString =
+ if Credential[EncryptConnection] = null or Credential[EncryptConnection] = true then
+ [
+ UseSSL = 1
+ ]
+ else
+ [
+ UseSSL = 0
+ ],
+
+ // Set host & port in connection string.
+ // Do not include port in connection string for aws server connection.
+ Server =
+ if Port <> null then
+ [
+ Host = Host,
+ Port = Port
+ ]
+ else
+ [
+ Host = Host
+ ],
+
ConnectionString = [
- Driver = "ODFE SQL ODBC Driver",
- Host = Host,
- Port = Port
+ Driver = "ODFE SQL ODBC Driver"
],
- OdbcDatasource = Odbc.DataSource(ConnectionString)
+
+ SQLGetTypeInfo = (types) =>
+ if (EnableTraceOutput <> true) then types else
+ let
+ // Outputting the entire table might be too large, and result in the value being truncated.
+ // We can output a row at a time instead with Table.TransformRows()
+ rows = Table.TransformRows(types, each Diagnostics.LogValue("SQLGetTypeInfo " & _[TYPE_NAME], _)),
+ toTable = Table.FromRecords(rows)
+ in
+ Value.ReplaceType(toTable, Value.Type(types)),
+
+ // SQLColumns is a function handler that receives the results of an ODBC call to SQLColumns().
+ SQLColumns = (catalogName, schemaName, tableName, columnName, source) =>
+ if (EnableTraceOutput <> true) then source else
+ // the if statement conditions will force the values to evaluated/written to diagnostics
+ if (Diagnostics.LogValue("SQLColumns.TableName", tableName) <> "***" and Diagnostics.LogValue("SQLColumns.ColumnName", columnName) <> "***") then
+ let
+ // Outputting the entire table might be too large, and result in the value being truncated.
+ // We can output a row at a time instead with Table.TransformRows()
+ rows = Table.TransformRows(source, each Diagnostics.LogValue("SQLColumns", _)),
+ toTable = Table.FromRecords(rows)
+ in
+ Value.ReplaceType(toTable, Value.Type(source))
+ else
+ source,
+
+ // Add support for `LIMIT` and `OFFSET` clauses (rather than `TOP`)
+ AstVisitor = [
+ // format is "LIMIT [,]" - ex. LIMIT 2,10 or LIMIT 10
+ LimitClause = (skip, take) =>
+ if (take = null) then
+ ...
+ else
+ let
+ skip =
+ if (skip = null or skip = 0) then
+ ""
+ else
+ Number.ToText(skip) & ","
+ in
+ [
+ Text = Text.Format("LIMIT #{0}#{1}", { skip, take }),
+ Location = "AfterQuerySpecification"
+ ]
+ ],
+
+ OdbcDatasource = Odbc.DataSource(ConnectionString & Server & CredentialConnectionString & EncryptedConnectionString, [
+ // Do not view the tables grouped by their schema names.
+ HierarchicalNavigation = false,
+ // Prevents execution of native SQL statements. Extensions should set this to true.
+ HideNativeQuery = true,
+ // Allows upconversion of numeric types
+ SoftNumbers = true,
+ // Allow upconversion / resizing of numeric and string types
+ TolerateConcatOverflow = true,
+ // Enables connection pooling via the system ODBC manager
+ ClientConnectionPooling = true,
+
+ // These values should be set by previous steps
+ AstVisitor = AstVisitor,
+ SQLColumns = SQLColumns,
+ SQLGetTypeInfo = SQLGetTypeInfo,
+
+ OnError = OnOdbcError,
+
+ // Connection string properties used for encrypted connections.
+ CredentialConnectionString = EncryptedConnectionString
+ ])
in
OdbcDatasource;
+// Handles ODBC errors.
+OnOdbcError = (errorRecord as record) =>
+ let
+ ErrorMessage = errorRecord[Message],
+ ConnectionHostPort = errorRecord[Detail][DataSourcePath],
+
+ IsDriverNotInstalled = Text.Contains(ErrorMessage, "doesn't correspond to an installed ODBC driver"),
+
+ OdbcError = errorRecord[Detail][OdbcErrors]{0},
+ OdbcErrorCode = OdbcError[NativeError],
+
+ // Failed to connect to given host
+ IsHostUnreachable =
+ OdbcErrorCode = 202
+ in
+ if IsDriverNotInstalled then
+ error Error.Record("", "The Open Distro For Elasticsearch SQL ODBC driver is not installed. Please install the driver")
+ else if IsHostUnreachable then
+ error Error.Record("", "Couldn't reach server. Please double-check the host, port and auth.")
+ else
+ error errorRecord;
+
// Data Source Kind description
OdfeSqlOdbcPBIConnector = [
+ // Required for use with Power BI Service.
+ TestConnection = (dataSourcePath) =>
+ let
+ json = Json.Document(dataSourcePath),
+ Host = json[Host],
+ Port = json[Port]
+ in
+ { "OdfeSqlOdbcPBIConnector.Contents", Host, Port },
+
+ // Authentication modes
Authentication = [
- Implicit = []
+ Implicit = [
+ Label = "NONE"
+ ],
+ UsernamePassword = [
+ Label = "BASIC"
+ ],
+ Key = [
+ Label = "AWS_SIGV4",
+ KeyLabel = "Region"
+ ]
],
+
+ // Enable Encryption
+ SupportsEncryption = true,
+
Label = Extension.LoadString("DataSourceLabel")
];
@@ -46,6 +207,7 @@ OdfeSqlOdbcPBIConnector.Publish = [
Category = "Other",
ButtonText = { Extension.LoadString("ButtonTitle"), Extension.LoadString("ButtonHelp") },
LearnMoreUrl = "https://opendistro.github.io/for-elasticsearch/",
+ SupportsDirectQuery = true,
SourceImage = OdfeSqlOdbcPBIConnector.Icons,
SourceTypeImage = OdfeSqlOdbcPBIConnector.Icons
];
@@ -54,3 +216,18 @@ OdfeSqlOdbcPBIConnector.Icons = [
Icon16 = { Extension.Contents("OdfeSqlOdbcPBIConnector16.png"), Extension.Contents("OdfeSqlOdbcPBIConnector20.png"), Extension.Contents("OdfeSqlOdbcPBIConnector24.png"), Extension.Contents("OdfeSqlOdbcPBIConnector32.png") },
Icon32 = { Extension.Contents("OdfeSqlOdbcPBIConnector32.png"), Extension.Contents("OdfeSqlOdbcPBIConnector40.png"), Extension.Contents("OdfeSqlOdbcPBIConnector48.png"), Extension.Contents("OdfeSqlOdbcPBIConnector64.png") }
];
+
+// Load common library functions
+Extension.LoadFunction = (name as text) =>
+ let
+ binary = Extension.Contents(name),
+ asText = Text.FromBinary(binary)
+ in
+ Expression.Evaluate(asText, #shared);
+
+// Diagnostics module contains multiple functions. .
+Diagnostics = Extension.LoadFunction("Diagnostics.pqm");
+Diagnostics.LogValue = if (EnableTraceOutput) then Diagnostics[LogValue] else (prefix, value) => value;
+
+// OdbcConstants contains numeric constants from the ODBC header files, and helper function to create bitfield values.
+ODBC = Extension.LoadFunction("OdbcConstants.pqm");
diff --git a/sql-odbc/src/PowerBIConnector/OdfeSqlOdbcPBIConnector.query.pq b/sql-odbc/src/PowerBIConnector/OdfeSqlOdbcPBIConnector.query.pq
index 7b2a564376..def55af3e2 100644
--- a/sql-odbc/src/PowerBIConnector/OdfeSqlOdbcPBIConnector.query.pq
+++ b/sql-odbc/src/PowerBIConnector/OdfeSqlOdbcPBIConnector.query.pq
@@ -1,5 +1,310 @@
-// Use this file to write queries to test your data connector
-let
- result = OdfeSqlOdbcPBIConnector.Contents()
-in
- result
\ No newline at end of file
+// This file contains queries to test your data connector
+section OdfeSqlOdbcPBIConnector.UnitTests;
+
+shared MyExtension.UnitTest =
+[
+ // Common variables for all tests
+ Host = "localhost",
+ Port = 9200,
+
+ facts =
+ {
+ Fact("Connection Test",
+ 7,
+ let
+ Source = OdfeSqlOdbcPBIConnector.Contents(Host,Port),
+ no_of_columns = Table.ColumnCount(Source)
+ in
+ no_of_columns
+ )
+ },
+
+ report = Facts.Summarize(facts)
+][report];
+
+/// COMMON UNIT TESTING CODE
+Fact = (_subject as text, _expected, _actual) as record =>
+[ expected = try _expected,
+ safeExpected = if expected[HasError] then "Expected : "& @ValueToText(expected[Error]) else expected[Value],
+ actual = try _actual,
+ safeActual = if actual[HasError] then "Actual : "& @ValueToText(actual[Error]) else actual[Value],
+ attempt = try safeExpected = safeActual,
+ result = if attempt[HasError] or not attempt[Value] then "Failure ⛔" else "Success ✓",
+ resultOp = if result = "Success ✓" then " = " else " <> ",
+ addendumEvalAttempt = if attempt[HasError] then @ValueToText(attempt[Error]) else "",
+ addendumEvalExpected = try @ValueToText(safeExpected) otherwise "...",
+ addendumEvalActual = try @ValueToText (safeActual) otherwise "...",
+ fact =
+ [ Result = result &" "& addendumEvalAttempt,
+ Notes =_subject,
+ Details = " ("& addendumEvalExpected & resultOp & addendumEvalActual &")"
+ ]
+][fact];
+
+Facts = (_subject as text, _predicates as list) => List.Transform(_predicates, each Fact(_subject,_{0},_{1}));
+
+Facts.Summarize = (_facts as list) as table =>
+[ Fact.CountSuccesses = (count, i) =>
+ [ result = try i[Result],
+ sum = if result[HasError] or not Text.StartsWith(result[Value], "Success") then count else count + 1
+ ][sum],
+ passed = List.Accumulate(_facts, 0, Fact.CountSuccesses),
+ total = List.Count(_facts),
+ format = if passed = total then "All #{0} Passed !!! ✓" else "#{0} Passed ☺ #{1} Failed ☹",
+ result = if passed = total then "Success" else "⛔",
+ rate = Number.IntegerDivide(100*passed, total),
+ header =
+ [ Result = result,
+ Notes = Text.Format(format, {passed, total-passed}),
+ Details = Text.Format("#{0}% success rate", {rate})
+ ],
+ report = Table.FromRecords(List.Combine({{header},_facts}))
+][report];
+
+ValueToText = (value, optional depth) =>
+ let
+ _canBeIdentifier = (x) =>
+ let
+ keywords = {"and", "as", "each", "else", "error", "false", "if", "in", "is", "let", "meta", "not", "otherwise", "or", "section", "shared", "then", "true", "try", "type" },
+ charAlpha = (c as number) => (c>= 65 and c <= 90) or (c>= 97 and c <= 122) or c=95,
+ charDigit = (c as number) => c>= 48 and c <= 57
+ in
+ try
+ charAlpha(Character.ToNumber(Text.At(x,0)))
+ and
+ List.MatchesAll(
+ Text.ToList(x),
+ (c)=> let num = Character.ToNumber(c) in charAlpha(num) or charDigit(num)
+ )
+ and not
+ List.MatchesAny( keywords, (li)=> li=x )
+ otherwise
+ false,
+
+ Serialize.Binary = (x) => "#binary(" & Serialize(Binary.ToList(x)) & ") ",
+
+ Serialize.Date = (x) => "#date(" &
+ Text.From(Date.Year(x)) & ", " &
+ Text.From(Date.Month(x)) & ", " &
+ Text.From(Date.Day(x)) & ") ",
+
+ Serialize.Datetime = (x) => "#datetime(" &
+ Text.From(Date.Year(DateTime.Date(x))) & ", " &
+ Text.From(Date.Month(DateTime.Date(x))) & ", " &
+ Text.From(Date.Day(DateTime.Date(x))) & ", " &
+ Text.From(Time.Hour(DateTime.Time(x))) & ", " &
+ Text.From(Time.Minute(DateTime.Time(x))) & ", " &
+ Text.From(Time.Second(DateTime.Time(x))) & ") ",
+
+ Serialize.Datetimezone =(x) => let
+ dtz = DateTimeZone.ToRecord(x)
+ in
+ "#datetimezone(" &
+ Text.From(dtz[Year]) & ", " &
+ Text.From(dtz[Month]) & ", " &
+ Text.From(dtz[Day]) & ", " &
+ Text.From(dtz[Hour]) & ", " &
+ Text.From(dtz[Minute]) & ", " &
+ Text.From(dtz[Second]) & ", " &
+ Text.From(dtz[ZoneHours]) & ", " &
+ Text.From(dtz[ZoneMinutes]) & ") ",
+
+ Serialize.Duration = (x) => let
+ dur = Duration.ToRecord(x)
+ in
+ "#duration(" &
+ Text.From(dur[Days]) & ", " &
+ Text.From(dur[Hours]) & ", " &
+ Text.From(dur[Minutes]) & ", " &
+ Text.From(dur[Seconds]) & ") ",
+
+ Serialize.Function = (x) => _serialize_function_param_type(
+ Type.FunctionParameters(Value.Type(x)),
+ Type.FunctionRequiredParameters(Value.Type(x)) ) &
+ " as " &
+ _serialize_function_return_type(Value.Type(x)) &
+ " => (...) ",
+
+ Serialize.List = (x) => "{" &
+ List.Accumulate(x, "", (seed,item) => if seed="" then Serialize(item) else seed & ", " & Serialize(item)) &
+ "} ",
+
+ Serialize.Logical = (x) => Text.From(x),
+
+ Serialize.Null = (x) => "null",
+
+ Serialize.Number = (x) =>
+ let Text.From = (i as number) as text =>
+ if Number.IsNaN(i) then "#nan" else
+ if i=Number.PositiveInfinity then "#infinity" else
+ if i=Number.NegativeInfinity then "-#infinity" else
+ Text.From(i)
+ in
+ Text.From(x),
+
+ Serialize.Record = (x) => "[ " &
+ List.Accumulate(
+ Record.FieldNames(x),
+ "",
+ (seed,item) =>
+ (if seed="" then Serialize.Identifier(item) else seed & ", " & Serialize.Identifier(item)) & " = " & Serialize(Record.Field(x, item))
+ ) &
+ " ] ",
+
+ Serialize.Table = (x) => "#table( type " &
+ _serialize_table_type(Value.Type(x)) &
+ ", " &
+ Serialize(Table.ToRows(x)) &
+ ") ",
+
+ Serialize.Text = (x) => """" &
+ _serialize_text_content(x) &
+ """",
+
+ _serialize_text_content = (x) => let
+ escapeText = (n as number) as text => "#(#)(" & Text.PadStart(Number.ToText(n, "X", "en-US"), 4, "0") & ")"
+ in
+ List.Accumulate(
+ List.Transform(
+ Text.ToList(x),
+ (c) => let n=Character.ToNumber(c) in
+ if n = 9 then "#(#)(tab)" else
+ if n = 10 then "#(#)(lf)" else
+ if n = 13 then "#(#)(cr)" else
+ if n = 34 then """""" else
+ if n = 35 then "#(#)(#)" else
+ if n < 32 then escapeText(n) else
+ if n < 127 then Character.FromNumber(n) else
+ escapeText(n)
+ ),
+ "",
+ (s,i)=>s&i
+ ),
+
+ Serialize.Identifier = (x) =>
+ if _canBeIdentifier(x) then
+ x
+ else
+ "#""" &
+ _serialize_text_content(x) &
+ """",
+
+ Serialize.Time = (x) => "#time(" &
+ Text.From(Time.Hour(x)) & ", " &
+ Text.From(Time.Minute(x)) & ", " &
+ Text.From(Time.Second(x)) & ") ",
+
+ Serialize.Type = (x) => "type " & _serialize_typename(x),
+
+
+ _serialize_typename = (x, optional funtype as logical) => /* Optional parameter: Is this being used as part of a function signature? */
+ let
+ isFunctionType = (x as type) => try if Type.FunctionReturn(x) is type then true else false otherwise false,
+ isTableType = (x as type) => try if Type.TableSchema(x) is table then true else false otherwise false,
+ isRecordType = (x as type) => try if Type.ClosedRecord(x) is type then true else false otherwise false,
+ isListType = (x as type) => try if Type.ListItem(x) is type then true else false otherwise false
+ in
+
+ if funtype=null and isTableType(x) then _serialize_table_type(x) else
+ if funtype=null and isListType(x) then "{ " & @_serialize_typename( Type.ListItem(x) ) & " }" else
+ if funtype=null and isFunctionType(x) then "function " & _serialize_function_type(x) else
+ if funtype=null and isRecordType(x) then _serialize_record_type(x) else
+
+ if x = type any then "any" else
+ let base = Type.NonNullable(x) in
+ (if Type.IsNullable(x) then "nullable " else "") &
+ (if base = type anynonnull then "anynonnull" else
+ if base = type binary then "binary" else
+ if base = type date then "date" else
+ if base = type datetime then "datetime" else
+ if base = type datetimezone then "datetimezone" else
+ if base = type duration then "duration" else
+ if base = type logical then "logical" else
+ if base = type none then "none" else
+ if base = type null then "null" else
+ if base = type number then "number" else
+ if base = type text then "text" else
+ if base = type time then "time" else
+ if base = type type then "type" else
+
+ /* Abstract types: */
+ if base = type function then "function" else
+ if base = type table then "table" else
+ if base = type record then "record" else
+ if base = type list then "list" else
+
+ "any /*Actually unknown type*/"),
+
+ _serialize_table_type = (x) =>
+ let
+ schema = Type.TableSchema(x)
+ in
+ "table " &
+ (if Table.IsEmpty(schema) then "" else
+ "[" & List.Accumulate(
+ List.Transform(
+ Table.ToRecords(Table.Sort(schema,"Position")),
+ each Serialize.Identifier(_[Name]) & " = " & _[Kind]),
+ "",
+ (seed,item) => (if seed="" then item else seed & ", " & item )
+ ) & "] " ),
+
+ _serialize_record_type = (x) =>
+ let flds = Type.RecordFields(x)
+ in
+ if Record.FieldCount(flds)=0 then "record" else
+ "[" & List.Accumulate(
+ Record.FieldNames(flds),
+ "",
+ (seed,item) =>
+ seed &
+ (if seed<>"" then ", " else "") &
+ (Serialize.Identifier(item) & "=" & _serialize_typename(Record.Field(flds,item)[Type]) )
+ ) &
+ (if Type.IsOpenRecord(x) then ",..." else "") &
+ "]",
+
+ _serialize_function_type = (x) => _serialize_function_param_type(
+ Type.FunctionParameters(x),
+ Type.FunctionRequiredParameters(x) ) &
+ " as " &
+ _serialize_function_return_type(x),
+
+ _serialize_function_param_type = (t,n) =>
+ let
+ funsig = Table.ToRecords(
+ Table.TransformColumns(
+ Table.AddIndexColumn( Record.ToTable( t ), "isOptional", 1 ),
+ { "isOptional", (x)=> x>n } ) )
+ in
+ "(" &
+ List.Accumulate(
+ funsig,
+ "",
+ (seed,item)=>
+ (if seed="" then "" else seed & ", ") &
+ (if item[isOptional] then "optional " else "") &
+ Serialize.Identifier(item[Name]) & " as " & _serialize_typename(item[Value], true) )
+ & ")",
+
+ _serialize_function_return_type = (x) => _serialize_typename(Type.FunctionReturn(x), true),
+
+ Serialize = (x) as text =>
+ if x is binary then try Serialize.Binary(x) otherwise "null /*serialize failed*/" else
+ if x is date then try Serialize.Date(x) otherwise "null /*serialize failed*/" else
+ if x is datetime then try Serialize.Datetime(x) otherwise "null /*serialize failed*/" else
+ if x is datetimezone then try Serialize.Datetimezone(x) otherwise "null /*serialize failed*/" else
+ if x is duration then try Serialize.Duration(x) otherwise "null /*serialize failed*/" else
+ if x is function then try Serialize.Function(x) otherwise "null /*serialize failed*/" else
+ if x is list then try Serialize.List(x) otherwise "null /*serialize failed*/" else
+ if x is logical then try Serialize.Logical(x) otherwise "null /*serialize failed*/" else
+ if x is null then try Serialize.Null(x) otherwise "null /*serialize failed*/" else
+ if x is number then try Serialize.Number(x) otherwise "null /*serialize failed*/" else
+ if x is record then try Serialize.Record(x) otherwise "null /*serialize failed*/" else
+ if x is table then try Serialize.Table(x) otherwise "null /*serialize failed*/" else
+ if x is text then try Serialize.Text(x) otherwise "null /*serialize failed*/" else
+ if x is time then try Serialize.Time(x) otherwise "null /*serialize failed*/" else
+ if x is type then try Serialize.Type(x) otherwise "null /*serialize failed*/" else
+ "[#_unable_to_serialize_#]"
+ in
+ try Serialize(value) otherwise "";
diff --git a/sql-odbc/src/PowerBIConnector/bin/Release/OdfeSqlOdbcPBIConnector.mez b/sql-odbc/src/PowerBIConnector/bin/Release/OdfeSqlOdbcPBIConnector.mez
index 02d8c023ae..dc5ae9d8ab 100644
Binary files a/sql-odbc/src/PowerBIConnector/bin/Release/OdfeSqlOdbcPBIConnector.mez and b/sql-odbc/src/PowerBIConnector/bin/Release/OdfeSqlOdbcPBIConnector.mez differ