persistentstorage/sql/SRC/Client/SqlDbSession.cpp
changeset 0 08ec8eefde2f
child 8 fa9941cf3867
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <e32math.h>
       
    17 #include <f32file.h>
       
    18 #include <f32file64.h>
       
    19 #include <s32strm.h>
       
    20 #include <s32mem.h>
       
    21 #include "IPCBuf.h"				//HIpcBuf
       
    22 #include "SqlDbSession.h"		//RSqlDbSession
       
    23 #include "SqlSrvStartup.h"		//StartSqlServer()
       
    24 #include "SqlResourceTest.h"	//TSqlResourceTestData
       
    25 #include "SqlSecurityImpl.h"	//CSqlSecurityPolicy
       
    26 
       
    27 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
    28 //////////////////////             TSqlFhCmdFunctor             ///////////////////////////////////////////////
       
    29 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
    30 
       
    31 /**
       
    32 TSqlFhCmdFunctor derived classes are used by RSqlDbSession for sending to SQL server localy created/opened 
       
    33 file handles.
       
    34 
       
    35 @see RSqlDbSession
       
    36 @see RSqlDbSession::CreateAndSendFileHandle()
       
    37 
       
    38 @internalComponent
       
    39 */
       
    40 NONSHARABLE_CLASS(TSqlFhCmdFunctor)
       
    41 	{
       
    42 public: 
       
    43 	TSqlFhCmdFunctor(RSqlDbSession& aDbSession, const TDesC& aDbFileName, const TDesC8* aConfig=NULL) :
       
    44 		iDbSession(aDbSession),
       
    45 		iDbFileName(aDbFileName),
       
    46 		iConfig(aConfig) // ownership not transferred
       
    47 		{
       
    48 		}
       
    49 	virtual TInt operator()(RFile64& aFile, TBool aCreated, TBool aReadOnly) = 0;
       
    50 	
       
    51 public:	
       
    52 	RSqlDbSession&	iDbSession;
       
    53 	const TDesC& 	iDbFileName;
       
    54 	const TDesC8*	iConfig;
       
    55 	};
       
    56 
       
    57 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
    58 //////////////////////              TSqlFhOpenCmdFunctor         //////////////////////////////////////////////
       
    59 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
    60 
       
    61 /**
       
    62 Implements the sending of ESqlSrvDbOpenFromHandle command to the SQL server.
       
    63 
       
    64 @internalComponent
       
    65 */
       
    66 NONSHARABLE_CLASS(TSqlFhOpenCmdFunctor) : public TSqlFhCmdFunctor
       
    67 	{
       
    68 public:	
       
    69 	TSqlFhOpenCmdFunctor(RSqlDbSession& aDbSession, const TDesC& aDbFileName,const TDesC8* aConfig=NULL) :
       
    70 		TSqlFhCmdFunctor(aDbSession, aDbFileName, aConfig)
       
    71 		{
       
    72 		}
       
    73 	virtual TInt operator()(RFile64& aDbFile, TBool aCreated, TBool aReadOnly);
       
    74 	
       
    75 	};
       
    76 
       
    77 /**
       
    78 Sends a command to the SQL server to use the supplied file session and file handles for adopting,
       
    79 when opening/creating a database.
       
    80 
       
    81 Usage of the IPC call arguments:
       
    82  - Arg 0: [out]  The 32 bits of the argument are used as follow:
       
    83  @code
       
    84  MSB                                                                                 LSB
       
    85  31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
       
    86  Ro Cr  C  C  C  C  C  C  C  C  C  C  C  C  C  C  F  F  F  F  F  F F F F F F F F F F F 
       
    87  @endcode
       
    88  Where:
       
    89  @code
       
    90   - "Ro" - read-only flag, true if the file is read-only;
       
    91   - "Cr" - create/open flag, true if the file was created, false if the file was opened;
       
    92   - "C"  - config string length;
       
    93   - "F"  - database file name length;
       
    94  @endcode
       
    95  - Arg 1: [out]  database file name + configuration string (if there is a configuration string)
       
    96  - Arg 2: [out]  file session handle
       
    97  - Arg 3: [out]  database file handle
       
    98 */		
       
    99 TInt TSqlFhOpenCmdFunctor::operator()(RFile64& aDbFile, TBool aCreated, TBool aReadOnly)
       
   100 	{
       
   101 	const TInt KConfigStrLen = iConfig ? iConfig->Length() : 0;
       
   102 	if(KConfigStrLen > KSqlSrvMaxConfigStrLen)
       
   103 		{
       
   104 		return KErrArgument;
       
   105 		}
       
   106 	TIpcArgs ipcArgs;
       
   107 	HBufC* arg1Buf = HBufC::New(iDbFileName.Length() + KConfigStrLen);
       
   108 	if(!arg1Buf)
       
   109 		{
       
   110 		return KErrNoMemory;	
       
   111 		}
       
   112 	TPtr arg1 = arg1Buf->Des();
       
   113 	arg1.Copy(iDbFileName);
       
   114 	if(iConfig)
       
   115 		{
       
   116 		TBuf<KSqlSrvMaxConfigStrLen> cfgBuf;
       
   117 		cfgBuf.Copy(*iConfig);
       
   118 		arg1.Append(cfgBuf);
       
   119 		}
       
   120 	TUint32 arg0 = iDbFileName.Length() | (KConfigStrLen << 16);
       
   121 	if(aReadOnly)
       
   122 		{
       
   123 		arg0 |= 0x80000000;	
       
   124 		}
       
   125 	if(aCreated)
       
   126 		{
       
   127 		arg0 |= 0x40000000;	
       
   128 		}
       
   129 	ipcArgs.Set(0, arg0);
       
   130 	ipcArgs.Set(1, &arg1);
       
   131 	TInt err = aDbFile.TransferToServer(ipcArgs, 2, 3);
       
   132 	if(err == KErrNone)
       
   133 		{
       
   134 		err = iDbSession.SendReceive(ESqlSrvDbOpenFromHandle, ipcArgs);
       
   135 		}
       
   136 	delete arg1Buf;	
       
   137 	return err;
       
   138 	}
       
   139 
       
   140 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   141 //////////////////////              TSqlFhAttachCmdFunctor         ////////////////////////////////////////////
       
   142 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   143 
       
   144 /**
       
   145 Implements the sending of ESqlSrvDbAttachFromHandle command to the SQL server.
       
   146 
       
   147 @internalComponent
       
   148 */
       
   149 NONSHARABLE_CLASS(TSqlFhAttachCmdFunctor) : public TSqlFhCmdFunctor
       
   150 	{
       
   151 public:	
       
   152 	TSqlFhAttachCmdFunctor(RSqlDbSession& aDbSession, const TDesC& aDbFileName,
       
   153 		const TDesC& aDbName) :
       
   154 		TSqlFhCmdFunctor(aDbSession, aDbFileName),
       
   155 		iDbName(aDbName)
       
   156 		{
       
   157 		}
       
   158 	virtual TInt operator()(RFile64& aDbFile, TBool aCreated, TBool aReadOnly);
       
   159 	
       
   160 private:
       
   161 	void SerializeToStreamL(RWriteStream& aStream);
       
   162 		
       
   163 private:
       
   164 	const TDesC&	iDbName;
       
   165 	
       
   166 	};
       
   167 	
       
   168 /**
       
   169 Sends a command to the SQL server to use the supplied file session and file handles for adopting,
       
   170 when attaching a database.
       
   171 
       
   172 Usage of the IPC call arguments:
       
   173  - Arg 0: [out]  The 32 bits of the argument are used as follow:
       
   174  @code
       
   175  MSB                                                                                 LSB
       
   176  31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
       
   177  Ro  F  F  F  F  F  F  F  F  F  F  F  F  F  F  F  F  F  F  F  F  F F F F F F F F F F F
       
   178  @endcode
       
   179  Where:
       
   180  @code
       
   181   - "Ro" - read-only flag, true if the file is read-only;
       
   182   - "F"  - database file name length;
       
   183  @endcode
       
   184  - Arg 1: [out]  db names buffer
       
   185  - Arg 2: [out]  file session handle
       
   186  - Arg 3: [out]  database file handle
       
   187 */		
       
   188 TInt TSqlFhAttachCmdFunctor::operator()(RFile64& aDbFile, TBool /*aCreated*/, TBool aReadOnly)
       
   189 	{
       
   190 	const TInt KMaxBufLen = iDbFileName.Length() * sizeof(TText) + iDbName.Length() * sizeof(TText) + 32;//"32" should be enough for all additional data like name length, alignment, etc.
       
   191 	HBufC8* buf = HBufC8::New(KMaxBufLen);
       
   192 	if(!buf)
       
   193 		{
       
   194 		return KErrNoMemory;	
       
   195 		}
       
   196 	TPtr8 bufPtr = buf->Des();
       
   197 	RDesWriteStream out(bufPtr);
       
   198 	TRAPD(err, SerializeToStreamL(out));
       
   199 	if(err == KErrNone)
       
   200 		{
       
   201 		TUint32 arg0 = (TUint32)bufPtr.Length() | (aReadOnly ? 0x80000000 : 0);
       
   202 		TIpcArgs ipcArgs(arg0, &bufPtr);
       
   203 		err = aDbFile.TransferToServer(ipcArgs, 2, 3);
       
   204 		if(err == KErrNone)
       
   205 			{
       
   206 			err = iDbSession.SendReceive(ESqlSrvDbAttachFromHandle, ipcArgs);
       
   207 			}
       
   208 		}
       
   209 	delete buf;
       
   210 	return err;
       
   211 	}
       
   212 	
       
   213 /**
       
   214 Serializes TSqlFhAttachCmdFunctor object content to a stream (aStream parameter).
       
   215 */
       
   216 void TSqlFhAttachCmdFunctor::SerializeToStreamL(RWriteStream& aStream)
       
   217 	{
       
   218 	aStream << iDbFileName;
       
   219 	aStream << iDbName;
       
   220 	aStream.CommitL();
       
   221 	}
       
   222 
       
   223 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   224 
       
   225 //Database type.
       
   226 enum TDbType 
       
   227 	{
       
   228 	EDbTypeUnknown,			//The database resides outside the client's private data cage 
       
   229 	EDbTypeClientPrivate	//The database resides in the client's private data cage
       
   230 	};
       
   231 
       
   232 /**
       
   233 Returns the database type.
       
   234 
       
   235 @param aDbFileName Database file name, including the path. If it is a request for creating/opening
       
   236 			secure database, then the name format is <drive>:<[SID]database_file_name>.
       
   237 
       
   238 @return EDbTypeClientPrivate If the database resides in the client's private data cage;
       
   239 		EDbTypeUnknown This may be a database in the SQL server private data cage or somewhere else;
       
   240 		If the error code is less than 0, then the function cannot determine the database type
       
   241 		(the function was unable to connect the local file session instance).
       
   242 
       
   243 @internalComponent
       
   244 */
       
   245 static TInt GetDbType(const TDesC& aDbFileName)
       
   246 	{
       
   247 	RFs fs;
       
   248 	TInt err = fs.Connect();
       
   249 	if(err == KErrNone)
       
   250 		{
       
   251 		TFileName clientPrivatePath;
       
   252 		err = fs.PrivatePath(clientPrivatePath);
       
   253 		fs.Close();
       
   254 		if(err == KErrNone)
       
   255 			{
       
   256 			TInt pos = aDbFileName.FindF(clientPrivatePath);
       
   257 			return (TUint)pos <= (TUint)KMaxDriveName ? EDbTypeClientPrivate : EDbTypeUnknown;
       
   258 			}
       
   259 		}
       
   260 	return err;
       
   261 	}
       
   262 
       
   263 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   264 //////////////////////                RSqlDbSession           /////////////////////////////////////////////////
       
   265 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   266 
       
   267 /**
       
   268 Establishes a connection with the SQL server.
       
   269 
       
   270 The method initializes RSqlDbSession object establishing a connection with the SQL server.
       
   271 If the connection has established successfully, the method sends a message to the server to
       
   272 create or open (depending on aFunction parameter) a database file with aDbFileName name.
       
   273 
       
   274 @param aFunction Specifies which operation has to be performed:
       
   275   ESqlSrvDbCreate       - Create a shared non-secure or private secure database;
       
   276   ESqlSrvDbCreateSecure - Create a shared secure database;
       
   277   ESqlSrvDbOpen         - Open a shared non-secure, shared secure or private secure database;
       
   278 
       
   279 @param aDbFileName Database file name, including the path. If it is a request for creating/opening
       
   280 			secure database, then the name format is <drive>:<[SID]database_file_name>.
       
   281 @param aSecurityPolicyData Security policy data. Non-empty descriptor only for secure databases
       
   282 @param aConfig the configuration string "PARAM=VALUE;...."
       
   283 
       
   284 @return KErrNone, the operation completed successfully;
       
   285 		KErrNoMemory, an out of memory condition has occured;
       
   286 		KErrBadName, bad database file name: zero length, directory name;
       
   287 		KErrAlreadyExists, database file already exists;
       
   288 		KErrNotReady, the drive does not exist or is not ready;
       
   289 		KErrInUse, the file has been opened already;
       
   290 		KErrNotFound, file not found;
       
   291 		KErrGeneral, no or invalid security policies (if the database to be opened is a secure database with bad security data);
       
   292 		KErrNotSupported, incompatible sql security version (if the database to be opened is a secure database with bad security data);
       
   293 		KErrPermissionDenied, the caller does not satisfy the relevant database security policies.
       
   294                       Note that database specific errors categorised as ESqlDbError, and
       
   295                       other system-wide error codes may also be returned.
       
   296         KErrArgument invalid config string or config string length exceeds KSqlSrvMaxConfigStrLen.
       
   297 
       
   298 Usage of the IPC call arguments:
       
   299  - Arg 0: [out]  database file name length
       
   300  - Arg 1: [out]  database file name
       
   301  - Arg 2: [out]  security policies buffer length if aFunction is ESqlSrvDbCreateSecure
       
   302  - Arg 3: [out]  security policies buffer if aFunction is ESqlSrvDbCreateSecure
       
   303 */
       
   304 TInt RSqlDbSession::Connect(TSqlSrvFunction aFunction, const TDesC& aDbFileName, const TDesC8& aSecurityPolicyData, const TDesC8* aConfig)
       
   305 	{
       
   306 	const TInt KDefaultMsgBufLen = 128;
       
   307 	iLastErrorMessage = HBufC::New(KDefaultMsgBufLen);
       
   308 	if(!iLastErrorMessage)
       
   309 		{
       
   310 		return KErrNoMemory;	
       
   311 		}
       
   312 	TInt err = DoCreateSession();
       
   313 	if(err == KErrNone)
       
   314 		{
       
   315 		err = InitResourceTestData();
       
   316 		if(err == KErrNone)
       
   317 			{
       
   318 			err = ::GetDbType(aDbFileName);
       
   319 			if(err >= 0)	
       
   320 				{
       
   321 				if(err == EDbTypeClientPrivate)
       
   322 					{//The database is in the client's private data cage. Set err = KErrPermissionDenied.
       
   323 					err = KErrPermissionDenied;
       
   324 					}
       
   325 				else
       
   326 					{//Unknown database type. Try to connect.
       
   327 					err = DoConnect(aFunction, aDbFileName, aSecurityPolicyData, aConfig);
       
   328 					}
       
   329 				if(err == KErrPermissionDenied && aFunction != ESqlSrvDbCreateSecure)
       
   330 					{
       
   331 					//What do we have here now? - the operation is create/open non-secure, the error is KErrPermissionDenied.
       
   332 					//So, the dll will try now to create/open the database in the application's private data cage.
       
   333 					//What if the used database file name was "C:MyDb.db"!? - the dll will try to create/open 
       
   334 					//"C:MyDb.db" in the application's data cage and there
       
   335 					//is a possibility that this operation my return a result, like KErrNotFound, which will hide the original
       
   336 					//error code (KErrPermissionDenied).
       
   337 					//The dll shall not try to create/open file in the application's data cage, if the format of the
       
   338 					//database file name is secure.
       
   339 					TParsePtrC parse(aDbFileName);//this call may panic if aDbFileName cannot be parsed, but it will panic the client
       
   340 					if(parse.PathPresent())
       
   341 						{
       
   342 						//The caller or the SQL server has no enough rights to create or open the database with aDbFileName name.
       
   343 						//One of the reasons may be that the database file is in the caller's private data cage where the SQL
       
   344 						//server cannot create/open the database file.
       
   345 						//The SQL dll will try to create/open the database file  on the client side and pass the file handle to the
       
   346 						//SQL server.
       
   347 						TSqlFhOpenCmdFunctor fhOpenCmdSender(*this, aDbFileName, aConfig);
       
   348 						err = CreateAndSendFileHandle(fhOpenCmdSender,
       
   349 							aFunction == ESqlSrvDbCreate ? RSqlDbSession::EDbfCreate : RSqlDbSession::EDbfOpen);
       
   350 						}
       
   351 					}	
       
   352 				}
       
   353 			}
       
   354 		}
       
   355 	if(err != KErrNone)
       
   356 		{
       
   357 		Close();	
       
   358 		}
       
   359 	return err;
       
   360 	}
       
   361 
       
   362 /**
       
   363 Sends a command to the server to attach an existing database to the current connection.
       
   364 
       
   365 The database can be:
       
   366 @code
       
   367  - shared secure database;
       
   368  - shared non-secure database;
       
   369  - private secure database;
       
   370 @endcode
       
   371 
       
   372 @param aDbFileName Database file name.
       
   373 @param aDbName Logical database name. 
       
   374 
       
   375 @return KErrNone, the operation completed successfully;
       
   376 		KErrNoMemory, an out of memory condition has occured;
       
   377 		KErrBadName, bad database file name: zero length, directory name;
       
   378 		KErrNotReady, the drive does not exist or is not ready;
       
   379 		KErrInUse, the file has been opened already;
       
   380 		KErrNotFound, file not found;
       
   381 		KErrGeneral, no or invalid security policies (if the database to be opened is a secure database with bad security data);
       
   382 		KErrNotSupported, incompatible sql security version (if the database to be opened is a secure database with bad security data);
       
   383 		KErrPermissionDenied, the caller does not satisfy the relevant database security policies.
       
   384                       Note that database specific errors categorised as ESqlDbError, and
       
   385                       other system-wide error codes may also be returned.
       
   386 
       
   387 Usage of the IPC call arguments: 
       
   388 Arg 0: [out]	Database file name length.
       
   389 Arg 1: [out]	Database file name.
       
   390 Arg 2: [out]	Logical database name length.
       
   391 Arg 3: [out]	Logical database name.
       
   392 */
       
   393 TInt RSqlDbSession::Attach(const TDesC& aDbFileName, const TDesC& aDbName)
       
   394 	{
       
   395 	TInt err = ::GetDbType(aDbFileName);
       
   396 	if(err >= 0)	
       
   397 		{
       
   398 		if(err == EDbTypeClientPrivate)
       
   399 			{//The database is in the client's private data cage. Set err = KErrPermissionDenied.
       
   400 			err = KErrPermissionDenied;
       
   401 			}
       
   402 		else
       
   403 			{//Unknown database type. Try to attach.
       
   404 			err = SendReceive(ESqlSrvDbAttach, TIpcArgs(aDbFileName.Length(), &aDbFileName, aDbName.Length(), &aDbName));
       
   405 			}
       
   406 		if(err == KErrPermissionDenied)
       
   407 			{
       
   408 			//What do we have here now? - the operation is "attach", the error is KErrPermissionDenied.
       
   409 			//Which means, it is (possibly) a secure database in the server private data cage and the caller 
       
   410 			//failed to pass the security checks.
       
   411 			//So, the dll will try now to open the database assuming it is in the application's private data cage
       
   412 			//and pass the file and session handles to the server which will try to attach the database using the handles.
       
   413 			//What if the used database file name was "C:MyDb.db"!? (which means that the client's intention was
       
   414 			//to attach a public shared secure database)
       
   415 			//The dll will try to open "C:MyDb.db" in the application's data cage and there
       
   416 			//is a possibility that this operation may return a result, like KErrNotFound, which will
       
   417 			//hide the original error code (KErrPermissionDenied).
       
   418 			//The dll shall not try to attach a database from the application's data cage, if the format of the
       
   419 			//database file name is secure.
       
   420 			TParsePtrC parse(aDbFileName);//this call may panic if aDbFileName cannot be parsed, but it will panic the client
       
   421 			if(parse.PathPresent())
       
   422 				{
       
   423 				TSqlFhAttachCmdFunctor fhAttachCmdSender(*this, aDbFileName, aDbName);
       
   424 				err = CreateAndSendFileHandle(fhAttachCmdSender, RSqlDbSession::EDbfOpen);
       
   425 				}
       
   426 			}
       
   427 		}
       
   428 	return err;
       
   429 	}
       
   430 	
       
   431 /**
       
   432 Copies a database.
       
   433 
       
   434 The method establishes a temporary connection with the SQL server and issues a request for copying
       
   435 aSrcDbFileName database file to aDestDbFileName file. After the server completes the request 
       
   436 CopyDatabase() closes the connection.
       
   437 
       
   438 @param aSrcDbFileName Source database file name.
       
   439 @param aDestDbFileName Destination database file name.
       
   440 
       
   441 @return KErrNone, the operation completed successfully;
       
   442 		KErrNoMemory, an out of memory condition has occured;
       
   443 		KErrBadName, bad database file name: zero length, directory name;
       
   444 		KErrAlreadyExists, target database file already exists;
       
   445 		KErrNotReady, the drive does not exist or is not ready;
       
   446 		KErrInUse, the file has been opened already;
       
   447 		KErrNotFound, file not found;
       
   448         KErrPermissionDenied, the SID of the calling application does not match the SID of source or destination database.
       
   449                       Note that other system-wide error codes may also be returned.
       
   450 
       
   451 Usage of the IPC call arguments: 
       
   452 Arg 0: [out]  source database file name length
       
   453 Arg 1: [out]  source database file name
       
   454 Arg 2: [out]  destination database file name length
       
   455 Arg 3: [out]  destination database file name
       
   456 */
       
   457 TInt RSqlDbSession::CopyDatabase(const TDesC& aSrcDbFileName, const TDesC& aDestDbFileName)
       
   458 	{
       
   459 	RSqlDbSession sess;
       
   460 	TInt err = sess.DoCreateSession();
       
   461 	if(err == KErrNone)
       
   462 		{
       
   463 		err = sess.InitResourceTestData();
       
   464 		if(err == KErrNone)
       
   465 			{
       
   466 			err = sess.SendReceive(ESqlSrvDbCopy, TIpcArgs(aSrcDbFileName.Length(), &aSrcDbFileName, aDestDbFileName.Length(), &aDestDbFileName));
       
   467 			}
       
   468 		sess.Close();
       
   469 		}
       
   470 	return err;
       
   471 	}
       
   472 
       
   473 /**
       
   474 Deletes a database.
       
   475 
       
   476 The database can be:
       
   477 @code
       
   478  - shared secure database;
       
   479  - shared non-secure database;
       
   480  - private secure database;
       
   481 @endcode
       
   482 
       
   483 The method establishes a temporary connection with the SQL server and issues a "delete" request regarding
       
   484 aDbFileName database file. After the server completes the request DeleteDatabase() closes the connection.
       
   485 
       
   486 @param aDbFileName Database file name. It must include the path if it is not a secure database.
       
   487 
       
   488 @return KErrNone, the operation completed successfully;
       
   489 		KErrNoMemory, an out of memory condition has occured;
       
   490 		KErrBadName, bad database file name: zero length, directory name;
       
   491 		KErrNotReady, the drive does not exist or is not ready;
       
   492 		KErrInUse, the file has been opened already;
       
   493 		KErrNotFound, file not found;
       
   494 		KErrAccessDenied, access to the database file is denied (it might be a read-only file);
       
   495         KErrPermissionDenied, the SID of the calling application does not match the SID of the database.
       
   496                       Note that other system-wide error codes may also be returned.
       
   497                       
       
   498 Usage of the IPC call arguments: 
       
   499 Arg 0: [out]  database file name length
       
   500 Arg 1: [out]  database file name
       
   501 */
       
   502 TInt RSqlDbSession::DeleteDatabase(const TDesC& aDbFileName)
       
   503 	{
       
   504 	RSqlDbSession sess;
       
   505 	TInt err = sess.DoCreateSession();
       
   506 	if(err == KErrNone)
       
   507 		{
       
   508 		err = sess.InitResourceTestData();
       
   509 		if(err == KErrNone)
       
   510 			{
       
   511 			err = ::GetDbType(aDbFileName);
       
   512 			if(err >= 0)	
       
   513 				{
       
   514 				if(err == EDbTypeClientPrivate)
       
   515 					{//The database is in the client's private data cage. Set err = KErrPermissionDenied.
       
   516 					err = KErrPermissionDenied;
       
   517 					}
       
   518 				else
       
   519 					{//Unknown database type. Try to delete.
       
   520 					err = sess.SendReceive(ESqlSrvDbDelete, TIpcArgs(aDbFileName.Length(), &aDbFileName));
       
   521 					}
       
   522 				if(err == KErrPermissionDenied)
       
   523 					{
       
   524 					//What do we have here now? - the operation is "delete db", the error is KErrPermissionDenied.
       
   525 					//So, the dll will try now to delete a database with the same name from the application's private data cage.
       
   526 					//What if the used database file name was "C:MyDb.db" and there is a such file in server's private
       
   527 					//data cage? - the dll will try to delete a file with name "C:MyDb.db" from the application's data cage 
       
   528 					//and there is a possibility that this operation my pass or may return strange result, like KErrNotFound.
       
   529 					//Bith cases are not what the user would expect.
       
   530 					//The dll shall not try to delete a file from the application's data cage, if the format of the
       
   531 					//database file name is secure.
       
   532 					TParsePtrC parse(aDbFileName);//this call may panic if aDbFileName cannot be parsed, but it will panic the client
       
   533 					if(parse.PathPresent())
       
   534 						{
       
   535 						//The caller or the SQL server has no enough rights to delete the database with aDbFileName name.
       
   536 						//One of the reasons may be that the database file is in the caller's private data cage where the SQL
       
   537 						//server cannot delete the database file.
       
   538 						//The SQL dll will try to delete the database file on the client side.
       
   539 						RFs fs;
       
   540 						err = fs.Connect();
       
   541 						if(err == KErrNone)
       
   542 							{
       
   543 							err = fs.Delete(aDbFileName);
       
   544 							fs.Close();
       
   545 							}
       
   546 						}
       
   547 					}
       
   548 				}
       
   549 			}
       
   550 		sess.Close();
       
   551 		}
       
   552 	return err;
       
   553 	}
       
   554 
       
   555 /**
       
   556 Retrieves a reference to the textual description of the error returned by the
       
   557 most recent call to any of the functions:
       
   558 - RSqlDatabase::Exec()
       
   559 - RSqlStatement::Exec()
       
   560 - RSqlStatement::Next()
       
   561 - RSqlStatement::Reset()
       
   562 
       
   563 Note that the function can only return a reference to text for
       
   564 database-specific type errors, i.e. those errors that are categorised as of
       
   565 type ESqlDbError.
       
   566 
       
   567 If an error occurs during the retrieval of the last error message, the function silently ignores the error
       
   568 and returns a NULL descriptor.
       
   569 
       
   570 @return A non-modifiable pointer descriptor representing the most recent error
       
   571         message. Note that message may be NULL, i.e. the descriptor may have
       
   572         zero length.
       
   573 
       
   574 Usage of the IPC call arguments:
       
   575 Arg 0: [out]	max length of the message buffer
       
   576 Arg 1: [in/out]	buffer for the last error message
       
   577 */
       
   578 TPtrC RSqlDbSession::LastErrorMessage()
       
   579 	{
       
   580 	TPtr msg(iLastErrorMessage->Des());
       
   581 	msg.Zero();
       
   582 	TInt size = 0;
       
   583 	while((size = SendReceive(ESqlSrvLastErrorMsg, TIpcArgs(msg.MaxLength(), &msg))) > KSqlClientBufOverflowCode)
       
   584 		{
       
   585 		HBufC* newMsgBuf = iLastErrorMessage->ReAlloc(size - KSqlClientBufOverflowCode);
       
   586 		if(!newMsgBuf)
       
   587 			{
       
   588 			break;	
       
   589 			}
       
   590 		iLastErrorMessage = newMsgBuf;	
       
   591 		msg.Set(iLastErrorMessage->Des());
       
   592 		}
       
   593 	return msg;
       
   594 	}
       
   595 
       
   596 /**
       
   597 Returns the ROWID of the most recent successful INSERT into the database 
       
   598 from this database connection.
       
   599 
       
   600 @return >0, the ROWID of the most recent successful INSERT into the database
       
   601 			from this database connection;
       
   602 		0, 	if no successful INSERTs have ever occurred from this database connection
       
   603 		<0, if one of the system-wide error codes is returned
       
   604 
       
   605 Usage of the IPC call arguments:
       
   606 Arg 0: [in/out]	the receiving buffer for the last inserted ROWID
       
   607 */	
       
   608 TInt64 RSqlDbSession::LastInsertedRowId()
       
   609 	{
       
   610 	TInt64 res;
       
   611 	TPtr8 ptr(reinterpret_cast <TUint8*> (&res), sizeof(res));
       
   612 	TInt err = SendReceive(ESqlSrvDbLastInsertedRowId, TIpcArgs(&ptr));
       
   613 	return err == KErrNone ? res : err;
       
   614 	}
       
   615 
       
   616 /**
       
   617 Retrieves the database security policies.
       
   618 
       
   619 @return A pointer to the created and internalized CSqlSecurityPolicy instance.
       
   620 
       
   621 @return KErrNone, the operation has completed successfully;
       
   622 		KErrNoMemory, an out of memory condition has occurred;
       
   623                       Note that the function may leave with some database specific errors categorised as 
       
   624                       ESqlDbError or other system-wide error codes.
       
   625 
       
   626 Usage of the IPC call arguments:
       
   627 Arg 0: [out]	security policy buffer size
       
   628 Arg 1: [in/out]	buffer for the database security policies
       
   629 */
       
   630 TInt RSqlDbSession::GetSecurityPolicy(RSqlBufFlat& aSecurityPolicyBuf)
       
   631 	{
       
   632 	TPtr8 ptr(aSecurityPolicyBuf.BufPtr());
       
   633 	TInt rc = KErrNone;
       
   634 	while((rc = SendReceive(ESqlSrvDbGetSecurityPolicy, TIpcArgs(ptr.MaxLength(), &ptr))) > KSqlClientBufOverflowCode)
       
   635 		{
       
   636 		rc = aSecurityPolicyBuf.ReAlloc(rc - KSqlClientBufOverflowCode);
       
   637 		if(rc != KErrNone)
       
   638 			{
       
   639 			break;
       
   640 			}
       
   641 		ptr.Set(aSecurityPolicyBuf.BufPtr());
       
   642 		}
       
   643 	return rc;
       
   644 	}
       
   645 	
       
   646 /**
       
   647 Closes the database and releases the connection with the database server.
       
   648 */
       
   649 void RSqlDbSession::Close()
       
   650 	{
       
   651 	if(Handle())
       
   652 		{
       
   653 		(void)SendReceive(ESqlSrvDbClose);
       
   654 		}
       
   655 	TSqlResourceTestData::Release();
       
   656 	delete iLastErrorMessage;
       
   657 	iLastErrorMessage = NULL;
       
   658 	RSessionBase::Close();
       
   659 	}
       
   660 
       
   661 /**
       
   662 The method establishes a connection with the SQL server.
       
   663 
       
   664 @return KErrNone, The connection was established successfully;
       
   665 		KErrAlreadyExists, the connection already exists.
       
   666                  The function may also return some other system-wide error codes.
       
   667 */
       
   668 TInt RSqlDbSession::DoCreateSession()
       
   669 	{
       
   670 	const TInt KTimesToRetryConnection = 2;
       
   671 	TInt retry = KTimesToRetryConnection;
       
   672 	for(;;)
       
   673 		{
       
   674 		TInt err = CreateSession(KSqlSrvName, ::SqlSrvVersion());
       
   675 		if(err != KErrNotFound && err != KErrServerTerminated)
       
   676 			{
       
   677 			return err;
       
   678 			}
       
   679 		if(--retry == 0)
       
   680 			{
       
   681 			return err;
       
   682 			}
       
   683 		err = ::StartSqlServer();
       
   684 		if(err != KErrNone && err != KErrAlreadyExists)
       
   685 			{
       
   686 			return err;
       
   687 			}
       
   688 		}
       
   689 	}
       
   690 
       
   691 /**
       
   692 The method gets called immediatelly after the establishing client-server connection but before the 
       
   693 create/open database message. 
       
   694 If a request was made by the client (using TSqlResourceTester methods) to test the server under out of memory
       
   695 conditions, InitResourceTestData() will send this request to the server, putting the just created connection
       
   696 in a "out of memory" test mode.
       
   697 */
       
   698 TInt RSqlDbSession::InitResourceTestData()
       
   699 	{
       
   700 	TInt err = KErrNone;
       
   701 #ifdef _DEBUG	
       
   702 	TSqlResourceTestData* data = TSqlResourceTestData::Instance();
       
   703 	if(data)
       
   704 		{
       
   705 		data->Init(*this);
       
   706 		}
       
   707 	else
       
   708 		{
       
   709 		err = KErrNoMemory;	
       
   710 		}
       
   711 #endif	
       
   712 	return err;	
       
   713 	}
       
   714 
       
   715 /**
       
   716 Creates/opens database file locally and sends the file handle to the SQL server.
       
   717 
       
   718 This function is used only when the SQL server fails to create/open/attach the requested database file with
       
   719 KErrPermissionDenied error. One of the reasons for that error may be that the database file is in the 
       
   720 calling application's private data cage. In this case an attempt is made to create/open the database file locally
       
   721 and if the operation completes successfully, then the file handle is passed to the SQL server.
       
   722 
       
   723 @param aFhCmdSender A reference to a functor instance which is used for sending the file handles to the SQL server. 
       
   724 @param aDbfAction It is set by the caller to RSqlDbSession::EDbfCreate if the database file has to be created or
       
   725 				  to RSqlDbSession::EDbfOpen if the database file already exists and has to be opened
       
   726 
       
   727 @return KErrNone, the operation completed successfully;
       
   728 		KErrNoMemory, an out of memory condition has occured;
       
   729 		KErrBadName, bad database file name: zero length, directory name, missing drive in the file name;
       
   730 		KErrAlreadyExists, database file already exists;
       
   731 		KErrNotReady, the drive does not exist or is not ready;
       
   732 		KErrInUse, the file has been opened already;
       
   733 		KErrNotFound, file not found;
       
   734 		KErrPermissionDenied, the caller does not satisfy the relevant database security policies.
       
   735                       Note that database specific errors categorised as ESqlDbError, and
       
   736                       other system-wide error codes may also be returned.
       
   737 */
       
   738 TInt RSqlDbSession::CreateAndSendFileHandle(TSqlFhCmdFunctor& aFhCmdSender, RSqlDbSession::TDbfAction aDbfAction)
       
   739 	{
       
   740 	//Create a file session
       
   741 	RFs fs;
       
   742 	TInt err = fs.Connect();
       
   743 	if(err != KErrNone)
       
   744 		{
       
   745 		return err;	
       
   746 		}
       
   747 	//Share the file session
       
   748 	err = fs.ShareProtected();
       
   749 	if(err != KErrNone)
       
   750 		{
       
   751 		fs.Close();	
       
   752 		return err;	
       
   753 		}
       
   754 	//Create/open the database file locally
       
   755 	TBool readOnly = EFalse;
       
   756 	TBool fileCreated = EFalse;
       
   757 	RFile64 dbFile;
       
   758 	if(aDbfAction == RSqlDbSession::EDbfCreate)
       
   759 		{//Create the database file in R/W mode
       
   760 		err = dbFile.Create(fs, aFhCmdSender.iDbFileName, EFileShareAny | EFileWrite);
       
   761 		if(err == KErrNone)
       
   762 			{
       
   763 			fileCreated = ETrue;	
       
   764 			}
       
   765 		}
       
   766 	else //aDbfAction == RSqlDbSession::EDbfOpen
       
   767 		{//Open the database file in shared R/W mode
       
   768 		err = dbFile.Open(fs, aFhCmdSender.iDbFileName, EFileShareAny | EFileWrite);
       
   769 		if(err != KErrNone)
       
   770 			{//If the the database open operation in R/W mode has failed - try to open the database in shared read-only mode.
       
   771 			readOnly = ETrue;
       
   772 			err = dbFile.Open(fs, aFhCmdSender.iDbFileName, EFileShareReadersOnly);
       
   773 			}
       
   774 		}
       
   775 	if(err == KErrNone)
       
   776 		{//Successful create/open database file operation. Send the database file and session handles to the server.
       
   777 		err = aFhCmdSender(dbFile, fileCreated, readOnly);
       
   778 		dbFile.Close();
       
   779 		}
       
   780 	if(err != KErrNone && fileCreated)
       
   781 		{
       
   782 		dbFile.Close();
       
   783 		TInt err2 = fs.Delete(aFhCmdSender.iDbFileName);
       
   784 		if(err2 != KErrNone)
       
   785 			{//Sometimes it is not possible the file to be deleted, the reported error is - KErrInUse. 			
       
   786 			fs.Close();
       
   787 			User::After(100000);
       
   788 			err2 = fs.Connect();
       
   789 			if(err2 == KErrNone)
       
   790 				{
       
   791 				(void)fs.Delete(aFhCmdSender.iDbFileName);
       
   792 				}
       
   793 			}
       
   794 		}
       
   795 	fs.Close();	
       
   796 	return err;
       
   797 	}
       
   798 
       
   799 /**
       
   800 Prepares the "security & configuration" string and sends the command to the SQL server.
       
   801 
       
   802 @param aFunction Specifies which operation has to be performed:
       
   803   ESqlSrvDbCreate       - Create a shared non-secure or private secure database;
       
   804   ESqlSrvDbCreateSecure - Create a shared secure database;
       
   805   ESqlSrvDbOpen         - Open a shared non-secure, shared secure or private secure database;
       
   806 
       
   807 @param aDbFileName Database file name, including the path. If it is a request for creating/opening
       
   808 			secure database, then the name format is <drive>:<[SID]database_file_name>.
       
   809 @param aSecurityPolicyData Security policy data. Non-empty descriptor only for secure databases
       
   810 @param aConfig the configuration string "PARAM=VALUE;...."
       
   811 
       
   812 @return KErrNone, the operation completed successfully;
       
   813 		KErrNoMemory, an out of memory condition has occured;
       
   814         KErrArgument invalid config string or config string length exceeds KSqlSrvMaxConfigStrLen.
       
   815                      Other system-wide error codes may also be returned.
       
   816 		
       
   817 */
       
   818 TInt RSqlDbSession::DoConnect(TSqlSrvFunction aFunction, const TDesC& aDbFileName, const TDesC8& aSecurityPolicyData, const TDesC8* aConfig)
       
   819 	{
       
   820 	const TInt KConfigStrLen = aConfig ? aConfig->Length() : 0;
       
   821 	if(KConfigStrLen > KSqlSrvMaxConfigStrLen)
       
   822 		{
       
   823 		return KErrArgument;
       
   824 		}
       
   825 	const TInt KSecPolicyLen = aFunction == ESqlSrvDbCreateSecure ? aSecurityPolicyData.Length() : 0;
       
   826 	TIpcArgs ipcArgs(aDbFileName.Length(), &aDbFileName);
       
   827 	// pack the length xxxxyyyy where xxxx is the policy length
       
   828 	// and yyyy is the config length.
       
   829 	ipcArgs.Set(2, (TUint)(KSecPolicyLen << 16) | (TUint)KConfigStrLen);
       
   830 	const TInt KTotalLen = KConfigStrLen + KSecPolicyLen;
       
   831 	ipcArgs.Set(3, 0);
       
   832 	HBufC8* arg3Buf = NULL;
       
   833 	if(KTotalLen > 0)
       
   834 		{
       
   835 		arg3Buf = HBufC8::New(KTotalLen);
       
   836 		if(!arg3Buf)
       
   837 			{
       
   838 			return KErrNoMemory;
       
   839 			}
       
   840 		TPtr8 arg3Ptr = arg3Buf->Des();
       
   841 		if(KSecPolicyLen > 0)
       
   842 			{
       
   843 			arg3Ptr.Copy(aSecurityPolicyData);
       
   844 			}
       
   845 		if(KConfigStrLen > 0)
       
   846 			{
       
   847 			//coverity[DEADCODE]
       
   848 			//The ASSERT might be useful in catching future defect in this function
       
   849 			__SQLASSERT(aConfig != NULL, ESqlPanicInternalError);
       
   850 			arg3Ptr.Append(*aConfig);
       
   851 			}
       
   852 		ipcArgs.Set(3, &arg3Ptr);
       
   853 		}
       
   854 	TInt err = SendReceive(aFunction, ipcArgs);
       
   855 	delete arg3Buf;
       
   856 	return err;
       
   857 	}