On Tuesday 01 Jan 2008 7:48:11 pm Jarosław Staniek wrote:
> Sharan Rao said the following, On 2007-12-31 22:07:
> > Reviewing the code again, is passing only FieldList object enough ?
> > The tablename can be obtained from one of the fields in the FieldList.
> > But this would also lead to calculation of the tableName from the
> > FieldList object three times in most insertRecord() functions.
> > 1. Normal calculation in insertRecord()
> > 2. in drv_beforeInsert()
> > 3. in drv_afterInsert()
>
> Sharan, thanks for the patch; it's mostly OK.
> First note, could you please change spaces to tabs in the indentation?
> (even if we plan to switch to spaces soon I hope)
>
> * Move Connection::drv_beforeInsert(), etc. to the header file for
> efficiency. You'll need to put Q_UNUSED(table);, etc. there to avoid
> warnings about unused args.
> * Check results of calling these methods, i.e.
>     if (!drv_beforeInsert(...))
>       return false;
> * commit cursor.cpp change (removal of my commentout) as a separate
> checkin. * In SybaseConnection::drv_beforeInsert() you could put instead:
>
> +bool KexiDB::SybaseConnection::drv_beforeInsert( const QString& table,
> FieldList& fields )
> +{
> +
> +    if ( fields.autoIncrementFields()->isEmpty() )
> +          return true;
>       // explicit insertion into IDENTITY fields !!
>       return drv_executeSQL( QString::fromLatin1( "SET IDENTITY_INSERT %1
> ON" ).arg( table ) );
> +}
>
> Same for other 3 methods.
> BTW, don't we need escape the table name?

Attached new patch with discussed changes.

Cheers!
 Sharan Rao
Index: connection.cpp
===================================================================
--- connection.cpp	(revision 750995)
+++ connection.cpp	(working copy)
@@ -1045,9 +1045,18 @@
 
 #define C_INS_REC(args, vals) \
 	bool Connection::insertRecord(KexiDB::TableSchema &tableSchema args) {\
-		return executeSQL( \
-		 QString("INSERT INTO ") + escapeIdentifier(tableSchema.name()) + " VALUES (" + vals + ")" \
-		); \
+                 if ( !drv_beforeInsert( tableSchema.name(), tableSchema ) )  \
+                     return false;                                      \
+                                                                        \
+                 bool res = executeSQL(                                      \
+		 QString("INSERT INTO ") + escapeIdentifier(tableSchema.name()) \
+                 + " (" + tableSchema.sqlFieldsList(m_driver) + ") VALUES (" + vals + ")"      \
+		 ); \
+                                                                          \
+                 if ( !drv_afterInsert( tableSchema.name(),tableSchema ) ) \
+                     return false;                                      \
+                                                                        \
+                 return res;                                             \
 	}
 
 #define C_INS_REC_ALL \
@@ -1078,10 +1087,15 @@
 		vals \
 		it.toFront(); \
 		QString tableName( (it.hasNext() && it.peekNext()->table()) ? it.next()->table()->name() : "??" ); \
-		return executeSQL( \
+                if ( !drv_beforeInsert( tableName, fields ) )            \
+                    return false;                                       \
+                bool res = executeSQL(                                  \
 			QString("INSERT INTO ") + escapeIdentifier(tableName) \
 			+ "(" + fields.sqlFieldsList(m_driver) + ") VALUES (" + value + ")" \
 		); \
+                if ( !drv_afterInsert( tableName, fields ) )    \
+                    return false;                               \
+                return res;                             \
 	}
 
 C_INS_REC_ALL
@@ -1119,7 +1133,13 @@
 	m_sql += ")";
 
 //	KexiDBDbg<<"******** "<< m_sql << endl;
-	return executeSQL(m_sql);
+        if ( !drv_beforeInsert( tableSchema.name(), tableSchema ) )
+            return false;
+	bool res = executeSQL(m_sql);
+        if ( !drv_afterInsert( tableSchema.name(), tableSchema ) )
+            return false;
+
+        return res;
 }
 
 bool Connection::insertRecord(FieldList& fields, const QList<QVariant>& values)
@@ -1135,10 +1155,11 @@
 	m_sql.clear();
 	QList<QVariant>::ConstIterator it = values.constBegin();
 //	int i=0;
+        QString tableName = escapeIdentifier( flist->first()->table()->name() );
 	while (f && (it!=values.constEnd())) {
 		if (m_sql.isEmpty())
 			m_sql = QString("INSERT INTO ") +
-				escapeIdentifier(flist->first()->table()->name()) + "(" +
+				tableName + "(" +
 				fields.sqlFieldsList(m_driver) + ") VALUES (";
 		else
 			m_sql += ",";
@@ -1150,7 +1171,13 @@
 	}
 	m_sql += ")";
 
-	return executeSQL(m_sql);
+        if ( !drv_beforeInsert( tableName, fields ) )
+            return false;
+	bool res = executeSQL(m_sql);
+        if ( !drv_afterInsert( tableName, fields ) )
+            return false;
+
+        return res;
 }
 
 bool Connection::executeSQL( const QString& statement )
@@ -3306,7 +3333,17 @@
 	m_sql += (sqlset + " WHERE " + sqlwhere);
 	KexiDBDbg << " -- SQL == " << ((m_sql.length() > 400) ? (m_sql.left(400)+"[.....]") : m_sql) << endl;
 
-	if (!executeSQL(m_sql)) {
+        // preprocessing before update
+        if ( !drv_beforeUpdate( mt->name(), query ) )
+            return false;
+
+        bool res = executeSQL( m_sql );
+
+        // postprocessing after update
+        if ( !drv_afterUpdate( mt->name(), query ) )
+            return false;
+
+	if (!res) {
 		setError(ERR_UPDATE_SERVER_ERROR, i18n("Row updating on the server failed."));
 		return false;
 	}
@@ -3409,8 +3446,16 @@
 	m_sql += (sqlcols + ") VALUES (" + sqlvals + ")");
 //	KexiDBDbg << " -- SQL == " << m_sql << endl;
 
-	bool res = executeSQL(m_sql);
+        // do driver specific pre-processing
+        if ( !drv_beforeInsert( mt->name(), query) )
+            return false;
 
+        bool res = executeSQL(m_sql);
+
+        // do driver specific post-processing
+        if ( !drv_afterInsert( mt->name(), query) )
+            return false;
+
 	if (!res) {
 		setError(ERR_INSERT_SERVER_ERROR, i18n("Row inserting on the server failed."));
 		return false;
Index: connection.h
===================================================================
--- connection.h	(revision 750642)
+++ connection.h	(working copy)
@@ -1001,7 +1001,61 @@
 		*/
 		virtual bool drv_rollbackTransaction(TransactionData* trans);
 
-		/*! Changes autocommiting option for established connection.
+
+                /*! Preprocessing (if any) required by drivers before execution of an 
+                    Insert statement.
+		    Reimplement this method in your driver if there are any special processing steps to be
+		    executed before an Insert statement.
+
+                  \sa drv_afterInsert()
+                */
+                virtual bool drv_beforeInsert(const QString& table, FieldList& fields){
+		    Q_UNUSED(table);
+		    Q_UNUSED(fields);
+		    return true;
+		}
+
+                /*! Postprocessing (if any) required by drivers before execution of an 
+                    Insert statement.
+		    Reimplement this method in your driver if there are any special processing steps to be
+		    executed after an Insert statement.
+
+                  \sa drv_beforeInsert()
+                */
+                virtual bool drv_afterInsert(const QString& table, FieldList& fields){
+		    Q_UNUSED(table);
+		    Q_UNUSED(fields);
+		    return true;		    
+		}
+
+                /*! Preprocessing required by drivers before execution of an 
+                    Update statement.
+		    Reimplement this method in your driver if there are any special processing steps to be
+		    executed before an Update statement.
+
+                  \sa drv_afterUpdate()
+                */
+                virtual bool drv_beforeUpdate(const QString& table, FieldList& fields){
+		    Q_UNUSED(table);
+		    Q_UNUSED(fields);
+		    return true;
+		}
+ 
+                /*! Postprocessing required by drivers before execution of an 
+                    Insert statement.
+		    Reimplement this method in your driver if there are any special processing steps to be
+		    executed after an Update statement.
+
+                  \sa drv_beforeUpdate()
+                */
+                virtual bool drv_afterUpdate(const QString& table, FieldList& fields){
+		    Q_UNUSED(table);
+		    Q_UNUSED(fields);
+		    return true;
+		}
+
+
+ 		/*! Changes autocommiting option for established connection.
 		 \return true on success.
 		 
 		 Note for driver developers: reimplement this only if your engine
Index: drivers/sybase/sybasedriver.cpp
===================================================================
--- drivers/sybase/sybasedriver.cpp	(revision 750992)
+++ drivers/sybase/sybasedriver.cpp	(working copy)
@@ -57,7 +57,9 @@
         beh->_1ST_ROW_READ_AHEAD_REQUIRED_TO_KNOW_IF_THE_RESULT_IS_EMPTY=false;
         beh->USING_DATABASE_REQUIRED_TO_CONNECT=false;
 
-        beh->AUTO_INCREMENT_FIELD_OPTION="DEFAULT AUTOINCREMENT";
+        // for Sybase ASA this field is "DEFAULT AUTOINCREMENT"
+        // for MSSQL and Sybase ASE it's IDENTITY
+        beh->AUTO_INCREMENT_FIELD_OPTION="IDENTITY";
         beh->AUTO_INCREMENT_PK_FIELD_OPTION = beh->AUTO_INCREMENT_FIELD_OPTION + " PRIMARY KEY ";
 
         // confirm
@@ -169,12 +171,13 @@
             + QByteArray( "\"" ) ;
 }
 
-QString SybaseDriver::addLimitTo1(const QString& sql, bool add)
+QString SybaseDriver::addLimitTo1(const QString& sql, bool add )
 {
     // length of "select" is 6
     // eg: before:  select foo from foobar
     //     after:   select TOP 1 foo from foobar
-    return add ? sql.trimmed().insert( 6 , " TOP 1 " ) : sql;
+    QString returnString = sql.trimmed().insert( 6, " TOP 1 " );
+    return add ? returnString : sql;
 }
 
 #include "sybasedriver.moc"
Index: drivers/sybase/sybaseconnection_p.cpp
===================================================================
--- drivers/sybase/sybaseconnection_p.cpp	(revision 750992)
+++ drivers/sybase/sybaseconnection_p.cpp	(working copy)
@@ -175,7 +175,7 @@
         out<<" host = "<<hostName<<"\n";
 
         if ( data.port == 0 )
-            out<<" port = "<<2638<<"\n"; // default port to be used
+            out<<" port = "<<5000<<"\n"; // default port to be used
         else
             out<<" port = "<<data.port<<"\n";
 
@@ -241,8 +241,8 @@
        if ( dbuse( dbProcess, dbName.toLatin1().data() ) == SUCCEED ) {
            return true;
        }
-//       return false;
-       return true; // for testing
+
+       return false;
 }
 
 /*! Executes the given SQL statement on the server.
Index: drivers/sybase/sybaseconnection.cpp
===================================================================
--- drivers/sybase/sybaseconnection.cpp	(revision 750992)
+++ drivers/sybase/sybaseconnection.cpp	(working copy)
@@ -58,11 +58,11 @@
 
         QString serverVersionString;
 
-        if ( !querySingleString( "Select @@servername" , version.string, 0 , false ) ) {
+        if ( !querySingleString( "Select @@servername" , version.string ) ) {
               KexiDBDrvDbg << "Couldn't fetch server name" << endl;
         }
 
-        if ( !querySingleString( "Select @@version", serverVersionString , 0 , false ) ) {
+        if ( !querySingleString( "Select @@version", serverVersionString ) ) {
               KexiDBDrvDbg << "Couldn't fetch server version" << endl;
         }
 
@@ -97,16 +97,21 @@
         if ( queryStringList( "Select name from master..sysdatabases", list ) )
             return true;
 
- 	d->storeResult();
+// 	d->storeResult();
 //	setError(ERR_DB_SPECIFIC,mysql_error(d->mysql));
         return false;
 }
 
-bool SybaseConnection::drv_createDatabase( const QString &dbName) {
+bool SybaseConnection::drv_createDatabase( const QString &dbName)
+{
 	KexiDBDrvDbg << "SybaseConnection::drv_createDatabase: " << dbName << endl;
 	// mysql_create_db deprecated, use SQL here.
-	if (drv_executeSQL("CREATE DATABASE " + driver()->escapeString(dbName)))
-		return true;
+	if (drv_executeSQL("CREATE DATABASE " + dbName)) {
+            // set allow_nulls_by_default option to true
+            QString allowNullsQuery = QString( "sp_dboption %1, allow_nulls_by_default, true" ).arg( dbName );
+            if ( drv_executeSQL( allowNullsQuery.toLatin1().data() ) )
+                  return true;
+        }
 	d->storeResult();
 	return false;
 }
@@ -115,8 +120,9 @@
 {
 	Q_UNUSED(cancelled);
 	Q_UNUSED(msgHandler);
+
 //TODO is here escaping needed?
-	return d->useDatabase( driver()->escapeString( dbName ) );
+	return  d->useDatabase( dbName ) ;
 }
 
 bool SybaseConnection::drv_closeDatabase() {
@@ -137,7 +143,7 @@
 {
     int rowId;
 
-    querySingleNumber( "Select @@IDENTITY", rowId );
+    querySingleNumber( "Select @@IDENTITY", rowId  );
 
     return ( qint64 )rowId;
 }
@@ -174,7 +180,7 @@
 
 bool SybaseConnection::drv_getTablesList( QStringList &list )
 {
-    return queryStringList( "Select name from sysobjects where type='U'", list );
+        return queryStringList( "Select name from sysobjects where type='U'", list );
 }
 
 PreparedStatement::Ptr SybaseConnection::prepareStatement(PreparedStatement::StatementType type,
@@ -183,4 +189,50 @@
 	return KSharedPtr<PreparedStatement>( new SybasePreparedStatement(type, *d, fields) );
 }
 
+bool KexiDB::SybaseConnection::drv_beforeInsert( const QString& table, FieldList& fields )
+{
+
+        if (  fields.autoIncrementFields()->isEmpty() )
+            return true;
+
+        // explicit insertion into IDENTITY fields !!
+        return drv_executeSQL( QString( "SET IDENTITY_INSERT %1 ON" ).arg( escapeIdentifier( table ) ) );
+
+}
+
+bool KexiDB::SybaseConnection::drv_afterInsert( const QString& table, FieldList& fields )
+{
+        // should we instead just set a flag when an identity_insert has taken place and only check for that
+        // flag here ?
+
+        if ( fields.autoIncrementFields()->isEmpty() )
+            return true;
+
+        // explicit insertion into IDENTITY fields has taken place. Turn off IDENTITY_INSERT
+        return drv_executeSQL( QString( "SET IDENTITY_INSERT %1 OFF" ).arg( escapeIdentifier( table ) ) );
+
+}
+
+bool KexiDB::SybaseConnection::drv_beforeUpdate( const QString& table, FieldList& fields )
+{
+        if ( fields.autoIncrementFields()->isEmpty() )
+            return true;
+
+        // explicit update of IDENTITY fields has taken place.
+        return  drv_executeSQL( QString( "SET IDENTITY_UPDATE %1 ON" ).arg( escapeIdentifier(  table ) ) );
+}
+
+bool KexiDB::SybaseConnection::drv_afterUpdate( const QString& table, FieldList& fields )
+{
+        // should we instead just set a flag when an identity_update has taken place and only check for that
+        // flag here ?
+
+        if ( fields.autoIncrementFields()->isEmpty() )
+            return true;
+
+        // explicit insertion into IDENTITY fields has taken place. Turn off IDENTITY_INSERT
+        return  drv_executeSQL( QString( "SET IDENTITY_UPDATE %1 OFF" ).arg( escapeIdentifier( table ) ) );
+
+}
+
 #include "sybaseconnection.moc"
Index: drivers/sybase/sybasedriver.h
===================================================================
--- drivers/sybase/sybasedriver.h	(revision 750992)
+++ drivers/sybase/sybasedriver.h	(working copy)
@@ -48,7 +48,7 @@
 		virtual QByteArray drv_escapeIdentifier(const QByteArray& str) const;
 		virtual Connection *drv_createConnection( ConnectionData &conn_data );
 		virtual bool drv_isSystemFieldName( const QString& n ) const;
-                virtual QString addLimitTo1(const QString& sql, bool add);
+                virtual QString addLimitTo1(const QString& sql, bool add );
 
 	private:
 		static const char *keywords[];
Index: drivers/sybase/sybaseconnection.h
===================================================================
--- drivers/sybase/sybaseconnection.h	(revision 750992)
+++ drivers/sybase/sybaseconnection.h	(working copy)
@@ -73,10 +73,17 @@
 //TODO: move this somewhere to low level class (MIGRATION?)
 		virtual bool drv_containsTable( const QString &tableName );
 
+                virtual bool drv_beforeInsert( const QString& table, FieldList& fields );
+                virtual bool drv_afterInsert( const QString& table, FieldList& fields );
+                
+                virtual bool drv_beforeUpdate( const QString& table, FieldList& fields );
+                virtual bool drv_afterUpdate( const QString& table, FieldList& fields );
+
 		SybaseConnectionInternal* d;
 
 		friend class SybaseDriver;
 		friend class SybaseCursor;
+
 };
 
 }
_______________________________________________
Kexi mailing list
[email protected]
https://mail.kde.org/mailman/listinfo/kexi

Reply via email to