@@ -168,18 +168,31 @@ func (c *external) Create(ctx context.Context, mg *namespacedv1alpha1.User) (man
168168 }
169169 }
170170
171- loginQuery := fmt .Sprintf ("CREATE LOGIN %s WITH PASSWORD=%s" , mssql .QuoteIdentifier (meta .GetExternalName (mg )), mssql .QuoteValue (pw ))
172- if err := c .loginDB .Exec (ctx , xsql.Query {
173- String : loginQuery ,
174- }); err != nil {
175- return managed.ExternalCreation {}, errors .Wrapf (err , errCreateLogin , meta .GetExternalName (mg ))
176- }
171+ // Check if this should be a contained database user
172+ if mg .Spec .ForProvider .Contained != nil && * mg .Spec .ForProvider .Contained {
173+ // Create contained database user directly without LOGIN
174+ dbName := ptr .Deref (mg .Spec .ForProvider .Database , "" )
175+ userQuery := fmt .Sprintf ("USE %s; CREATE USER %s WITH PASSWORD = %s" , mssql .QuoteIdentifier (dbName ), mssql .QuoteIdentifier (meta .GetExternalName (mg )), mssql .QuoteValue (pw ))
176+ if err := c .userDB .Exec (ctx , xsql.Query {
177+ String : userQuery ,
178+ }); err != nil {
179+ return managed.ExternalCreation {}, errors .Wrapf (err , errCreateUser , meta .GetExternalName (mg ))
180+ }
181+ } else {
182+ // Create traditional LOGIN + USER approach
183+ loginQuery := fmt .Sprintf ("CREATE LOGIN %s WITH PASSWORD=%s" , mssql .QuoteIdentifier (meta .GetExternalName (mg )), mssql .QuoteValue (pw ))
184+ if err := c .loginDB .Exec (ctx , xsql.Query {
185+ String : loginQuery ,
186+ }); err != nil {
187+ return managed.ExternalCreation {}, errors .Wrapf (err , errCreateLogin , meta .GetExternalName (mg ))
188+ }
177189
178- userQuery := fmt .Sprintf ("CREATE USER %s FOR LOGIN %s" , mssql .QuoteIdentifier (meta .GetExternalName (mg )), mssql .QuoteIdentifier (meta .GetExternalName (mg )))
179- if err := c .userDB .Exec (ctx , xsql.Query {
180- String : userQuery ,
181- }); err != nil {
182- return managed.ExternalCreation {}, errors .Wrapf (err , errCreateUser , meta .GetExternalName (mg ))
190+ userQuery := fmt .Sprintf ("CREATE USER %s FOR LOGIN %s" , mssql .QuoteIdentifier (meta .GetExternalName (mg )), mssql .QuoteIdentifier (meta .GetExternalName (mg )))
191+ if err := c .userDB .Exec (ctx , xsql.Query {
192+ String : userQuery ,
193+ }); err != nil {
194+ return managed.ExternalCreation {}, errors .Wrapf (err , errCreateUser , meta .GetExternalName (mg ))
195+ }
183196 }
184197
185198 return managed.ExternalCreation {
@@ -194,11 +207,23 @@ func (c *external) Update(ctx context.Context, mg *namespacedv1alpha1.User) (man
194207 }
195208
196209 if changed {
197- query := fmt .Sprintf ("ALTER LOGIN %s WITH PASSWORD=%s" , mssql .QuoteIdentifier (meta .GetExternalName (mg )), mssql .QuoteValue (pw ))
198- if err := c .loginDB .Exec (ctx , xsql.Query {
199- String : query ,
200- }); err != nil {
201- return managed.ExternalUpdate {}, errors .Wrap (err , errUpdateUser )
210+ if mg .Spec .ForProvider .Contained != nil && * mg .Spec .ForProvider .Contained {
211+ // For contained users, use ALTER USER syntax with explicit USE statement
212+ dbName := ptr .Deref (mg .Spec .ForProvider .Database , "" )
213+ query := fmt .Sprintf ("USE %s; ALTER USER %s WITH PASSWORD = %s" , mssql .QuoteIdentifier (dbName ), mssql .QuoteIdentifier (meta .GetExternalName (mg )), mssql .QuoteValue (pw ))
214+ if err := c .userDB .Exec (ctx , xsql.Query {
215+ String : query ,
216+ }); err != nil {
217+ return managed.ExternalUpdate {}, errors .Wrap (err , errUpdateUser )
218+ }
219+ } else {
220+ // For traditional users, use ALTER LOGIN syntax
221+ query := fmt .Sprintf ("ALTER LOGIN %s WITH PASSWORD=%s" , mssql .QuoteIdentifier (meta .GetExternalName (mg )), mssql .QuoteValue (pw ))
222+ if err := c .loginDB .Exec (ctx , xsql.Query {
223+ String : query ,
224+ }); err != nil {
225+ return managed.ExternalUpdate {}, errors .Wrap (err , errUpdateUser )
226+ }
202227 }
203228
204229 return managed.ExternalUpdate {
@@ -212,25 +237,34 @@ func (c *external) Disconnect(ctx context.Context) error {
212237 return nil
213238}
214239
215- func (c * external ) Delete (ctx context.Context , mg * namespacedv1alpha1. User ) (managed. ExternalDelete , error ) {
216- query := fmt .Sprintf ("SELECT session_id FROM sys.dm_exec_sessions WHERE login_name = %s" , mssql .QuoteValue (meta . GetExternalName ( mg ) ))
240+ func (c * external ) killLoginSessions (ctx context.Context , loginName string ) error {
241+ query := fmt .Sprintf ("SELECT session_id FROM sys.dm_exec_sessions WHERE login_name = %s" , mssql .QuoteValue (loginName ))
217242 rows , err := c .userDB .Query (ctx , xsql.Query {String : query })
218243 if err != nil {
219- return managed. ExternalDelete {}, errors .Wrap (err , errCannotGetLogins )
244+ return errors .Wrap (err , errCannotGetLogins )
220245 }
221246 defer rows .Close () //nolint:errcheck
222247
223248 for rows .Next () {
224249 var sessionID int
225250 if err := rows .Scan (& sessionID ); err != nil {
226- return managed. ExternalDelete {}, errors .Wrap (err , errCannotGetLogins )
251+ return errors .Wrap (err , errCannotGetLogins )
227252 }
228253 if err := c .userDB .Exec (ctx , xsql.Query {String : fmt .Sprintf ("KILL %d" , sessionID )}); err != nil {
229- return managed. ExternalDelete {}, errors .Wrapf (err , errCannotKillLoginSession , sessionID , meta . GetExternalName ( mg ) )
254+ return errors .Wrapf (err , errCannotKillLoginSession , sessionID , loginName )
230255 }
231256 }
232- if err := rows .Err (); err != nil {
233- return managed.ExternalDelete {}, errors .Wrap (err , errCannotGetLogins )
257+ return rows .Err ()
258+ }
259+
260+ func (c * external ) Delete (ctx context.Context , mg * namespacedv1alpha1.User ) (managed.ExternalDelete , error ) {
261+ isContained := mg .Spec .ForProvider .Contained != nil && * mg .Spec .ForProvider .Contained
262+
263+ // Only kill sessions for traditional users with logins, not contained users
264+ if ! isContained {
265+ if err := c .killLoginSessions (ctx , meta .GetExternalName (mg )); err != nil {
266+ return managed.ExternalDelete {}, err
267+ }
234268 }
235269
236270 if err := c .userDB .Exec (ctx , xsql.Query {
@@ -239,10 +273,13 @@ func (c *external) Delete(ctx context.Context, mg *namespacedv1alpha1.User) (man
239273 return managed.ExternalDelete {}, errors .Wrapf (err , errDropUser , meta .GetExternalName (mg ))
240274 }
241275
242- if err := c .loginDB .Exec (ctx , xsql.Query {
243- String : fmt .Sprintf ("DROP LOGIN %s" , mssql .QuoteIdentifier (meta .GetExternalName (mg ))),
244- }); err != nil {
245- return managed.ExternalDelete {}, errors .Wrapf (err , errDropLogin , meta .GetExternalName (mg ))
276+ // Only drop LOGIN if this is not a contained user
277+ if ! isContained {
278+ if err := c .loginDB .Exec (ctx , xsql.Query {
279+ String : fmt .Sprintf ("DROP LOGIN %s" , mssql .QuoteIdentifier (meta .GetExternalName (mg ))),
280+ }); err != nil {
281+ return managed.ExternalDelete {}, errors .Wrapf (err , errDropLogin , meta .GetExternalName (mg ))
282+ }
246283 }
247284
248285 return managed.ExternalDelete {}, nil
0 commit comments