Repository: ibis-project/ibis

Issue:
feat(mssql): Explicit Integrated Auth for MSSQL Connections
### Is your feature request related to a problem?

Microsoft SQL Server and Windows allows for the use of [Integrated Windows Authentication](https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/integrated-windows-authentication) to connect to the database servers. Often this is also enforced as the only option, and only Windows credentials can be used, not username and password.

- Ibis does not have documentation on using Integrated Windows Authentication, however it is supported by PyODBC
- Ibis does not have explicit args in the MSSQL connection or a default behavior when username and password are 'None' to use Integrated Windows Authentication
- **con.table** does not seem to inherit the database from **ibis.mssql.connect**, and must use explicit args instead of just the table name with schema separated by a '.'

## Current Solution for Windows Integrated Authentication:

```python
import ibis
import pandas as pd

# Connect to the MS SQL Server database
conn = ibis.mssql.connect(
    host='my_server',
    user=None,
    password=None
    database='my_database',
    driver='SQL Server',          # ODBC Driver
    Trusted_Connection = 'yes'
)

# Query Table
tbl = con.table(name='my_table', schema='my_schema', database='my_database')
df = tbl.limit(20).to_pandas()

df.head()
```

### Describe the solution you'd like

1. Modify ibis.mssql.connect to assume 
2. Update Ibis [MSSQL backend documentation](https://ibis-project.org/backends/mssql) to include section for integrated / windows authentication.

## Proposed Solution for Windows Integrated Authentication

```python
import ibis
import pandas as pd

# If both user and password are set to None, assume Integrated Windows Authentication and set Trusted_Connection = 'yes'
con = ibis.mssql.connect(     
    host="my_server",
    database="my_database",
    driver='SQL Server'
)

# Query Table
tbl = con.table('my_schema.my_table')  # Use of MSSQL and a database being passed allows for single string to query table.
df = tbl.limit(20).to_pandas()

df.head()
```

### What version of ibis are you running?

8.0.0

### What backend(s) are you using, if any?

MSSQL

### Code of Conduct

- [X] I agree to follow this project's Code of Conduct


Discussion:
Hey @haydenbspence -- thanks for raising this and for figuring out the integrated auth pattern!
It's hard for us to document these things without first having a test environment, so user reports like this are _great_.

We can definitely put in the changes to assume intergrated auth when username and password are left unset, and we can document that new default behavior on the mssql backend docs page.

In re: this pattern:
```python
tbl = con.table('my_schema.my_table') 
```

that is something that we have on our radar, but it won't land right away.  We are currently in the process of deprecating the use of the word `schema` as it refers to database hierarchy because it is rife with semantic collisions.

In Ibis 9.0 (our next release), the new(ish) patterns will be:

database: a collection of tables
catalog: a collection of databases

`con.table("table_name", database=("db_name"))  # assuming current catalog from existing connection`

`con.table("table_name", database=("catalog.db_name"))  # explicit catalog.db path`

`con.table("table_name", database=("catalog", "db_name"))  # explicit catalog.db path`

Once those changes have landed in a release and we've removed the  `schema` keyword entirely, then we'll be in a better place to also support dotted string paths being passed directly to `con.table`.


Resolving patch:
diff --git a/ibis/backends/mssql/__init__.py b/ibis/backends/mssql/__init__.py
--- a/ibis/backends/mssql/__init__.py
+++ b/ibis/backends/mssql/__init__.py
@@ -76,6 +76,43 @@ def do_connect(
         driver: str | None = None,
         **kwargs: Any,
     ) -> None:
+        """Connect to MSSQL database.
+
+        Parameters
+        ----------
+        host
+            Address of MSSQL server to connect to.
+        user
+            Username.  Leave blank to use Integrated Authentication.
+        password
+            Password.  Leave blank to use Integrated Authentication.
+        port
+            Port of MSSQL server to connect to.
+        database
+            The MSSQL database to connect to.
+        driver
+            ODBC Driver to use.
+
+            On Mac and Linux this is usually 'FreeTDS'.
+
+            On Windows, it is usually one of:
+
+            - ODBC Driver 11 for SQL Server
+            - ODBC Driver 13 for SQL Server (for both 13 and 13.1)
+            - ODBC Driver 17 for SQL Server
+            - ODBC Driver 18 for SQL Server
+
+            See https://learn.microsoft.com/en-us/sql/connect/odbc/windows/system-requirements-installation-and-driver-files
+        kwargs
+            Additional keyword arguments to pass to PyODBC.
+        """
+
+        # If no user/password given, assume Windows Integrated Authentication
+        # and set "Trusted_Connection" accordingly
+        # see: https://learn.microsoft.com/en-us/sql/connect/odbc/linux-mac/using-integrated-authentication
+        if user is None and password is None:
+            kwargs.setdefault("Trusted_Connection", "yes")
+
         con = pyodbc.connect(
             user=user,
             server=host,


Test patch: