Browse Source

sqldb: Modified ftAutoinc behavior slightly to match Delphi behavior and allow updating of ftAutoInc fields for those db backends that support it. Added support for odbc ReadOnly fields. Patch from Lacak2 Mantis #22531

git-svn-id: trunk@22935 -
ludob 12 years ago
parent
commit
35f1339404

+ 1 - 12
packages/fcl-db/src/base/bufdataset.pas

@@ -2203,8 +2203,6 @@ Var ABuff        : TRecordBuffer;
     i            : integer;
     i            : integer;
     blobbuf      : tbufblobfield;
     blobbuf      : tbufblobfield;
     NullMask     : pbyte;
     NullMask     : pbyte;
-    li           : longint;
-    StoreReadOnly: boolean;
     ABookmark    : PBufBookmark;
     ABookmark    : PBufBookmark;
 
 
 begin
 begin
@@ -2227,16 +2225,7 @@ begin
     begin
     begin
     if assigned(FAutoIncField) then
     if assigned(FAutoIncField) then
       begin
       begin
-      li := FAutoIncValue;
-      // In principle all TAutoIncfields are read-only, but in theory it is
-      // possible to set readonly to false.
-      StoreReadOnly:=FAutoIncField.ReadOnly;
-      FAutoIncField.ReadOnly:=false;
-      try
-        FAutoIncField.SetData(@li);
-      finally
-        FAutoIncField.ReadOnly:=FAutoIncField.ReadOnly;
-      end;
+      FAutoIncField.AsInteger := FAutoIncValue;
       inc(FAutoIncValue);
       inc(FAutoIncValue);
       end;
       end;
 
 

+ 2 - 4
packages/fcl-db/src/base/fields.inc

@@ -1750,8 +1750,6 @@ constructor TAutoIncField.Create(AOwner: TComponent);
 begin
 begin
   Inherited Create(AOWner);
   Inherited Create(AOWner);
   SetDataType(ftAutoInc);
   SetDataType(ftAutoInc);
-  FReadOnly:=True;
-  FProviderFlags:=FProviderFlags-[pfInUpdate];
 end;
 end;
 
 
 Procedure TAutoIncField.SetAsLongint(AValue : Longint);
 Procedure TAutoIncField.SetAsLongint(AValue : Longint);
@@ -1760,8 +1758,8 @@ begin
   // Some databases allows insertion of explicit values into identity columns
   // Some databases allows insertion of explicit values into identity columns
   // (some of them also allows (some not) updating identity columns)
   // (some of them also allows (some not) updating identity columns)
   // So allow it at client side and leave check for server side
   // So allow it at client side and leave check for server side
-  if not(FDataSet.State in [dsFilter,dsSetKey,dsInsert]) then
-    DataBaseError(SCantSetAutoIncFields);
+  //if not(FDataSet.State in [dsFilter,dsSetKey,dsInsert]) then
+  //  DataBaseError(SCantSetAutoIncFields);
   inherited;
   inherited;
 end;
 end;
 
 

+ 2 - 1
packages/fcl-db/src/sqldb/mssql/mssqlconn.pp

@@ -643,7 +643,8 @@ begin
 }
 }
     with TFieldDef.Create(FieldDefs, FieldDefs.MakeNameUnique(FieldName), FieldType, FieldSize, (col.Null=0) and (not col.Identity), i) do
     with TFieldDef.Create(FieldDefs, FieldDefs.MakeNameUnique(FieldName), FieldType, FieldSize, (col.Null=0) and (not col.Identity), i) do
     begin
     begin
-      //if col.Updatable = 0 then Attributes := Attributes + [faReadonly];
+      // identity, timestamp and calculated column are not updatable
+      if col.Updatable = 0 then Attributes := Attributes + [faReadonly];
       case FieldType of
       case FieldType of
         ftBCD,
         ftBCD,
         ftFmtBCD: Precision := col.Precision;
         ftFmtBCD: Precision := col.Precision;

+ 18 - 2
packages/fcl-db/src/sqldb/odbc/odbcconn.pas

@@ -1076,7 +1076,7 @@ var
   ColName,TypeName:string;
   ColName,TypeName:string;
   FieldType:TFieldType;
   FieldType:TFieldType;
   FieldSize:word;
   FieldSize:word;
-  AutoIncAttr: SQLINTEGER;
+  AutoIncAttr, Updatable: SQLINTEGER;
 begin
 begin
   ODBCCursor:=cursor as TODBCCursor;
   ODBCCursor:=cursor as TODBCCursor;
 
 
@@ -1182,6 +1182,7 @@ begin
     // only one column per table can have identity attr.
     // only one column per table can have identity attr.
     if (FieldType in [ftInteger,ftLargeInt]) and (AutoIncAttr=SQL_FALSE) then
     if (FieldType in [ftInteger,ftLargeInt]) and (AutoIncAttr=SQL_FALSE) then
     begin
     begin
+      AutoIncAttr:=0;
       ODBCCheckResult(
       ODBCCheckResult(
         SQLColAttribute(ODBCCursor.FSTMTHandle,     // statement handle
         SQLColAttribute(ODBCCursor.FSTMTHandle,     // statement handle
                         i,                          // column number
                         i,                          // column number
@@ -1196,6 +1197,18 @@ begin
         FieldType:=ftAutoInc;
         FieldType:=ftAutoInc;
     end;
     end;
 
 
+    Updatable:=0;
+    ODBCCheckResult(
+      SQLColAttribute(ODBCCursor.FSTMTHandle,
+                      i,
+                      SQL_DESC_UPDATABLE,
+                      nil,
+                      0,
+                      nil,
+                      @Updatable),
+      SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not get updatable attribute for column %d.',[i]
+    );
+
     if FieldType=ftUnknown then // if unknown field type encountered, try finding more specific information about the ODBC SQL DataType
     if FieldType=ftUnknown then // if unknown field type encountered, try finding more specific information about the ODBC SQL DataType
     begin
     begin
       SetLength(TypeName,TypeNameDefaultLength); // also garantuees uniqueness
       SetLength(TypeName,TypeNameDefaultLength); // also garantuees uniqueness
@@ -1233,7 +1246,10 @@ begin
     end;
     end;
 
 
     // add FieldDef
     // add FieldDef
-    TFieldDef.Create(FieldDefs, FieldDefs.MakeNameUnique(ColName), FieldType, FieldSize, (Nullable=SQL_NO_NULLS) and (AutoIncAttr=SQL_FALSE), i);
+    with TFieldDef.Create(FieldDefs, FieldDefs.MakeNameUnique(ColName), FieldType, FieldSize, (Nullable=SQL_NO_NULLS) and (AutoIncAttr=SQL_FALSE), i) do
+    begin
+      if Updatable = 0{SQL_ATTR_READONLY} then Attributes := Attributes + [faReadonly];
+    end;
   end;
   end;
 end;
 end;
 
 

+ 2 - 2
packages/fcl-db/src/sqldb/sqldb.pp

@@ -1633,7 +1633,7 @@ var FieldNamesQuoteChars : TQuoteChars;
       begin
       begin
       UpdateWherePart(sql_where,x);
       UpdateWherePart(sql_where,x);
 
 
-      if (pfInUpdate in Fields[x].ProviderFlags) then
+      if (pfInUpdate in Fields[x].ProviderFlags) and (not Fields[x].ReadOnly) then
         sql_set := sql_set +FieldNamesQuoteChars[0] + fields[x].FieldName + FieldNamesQuoteChars[1] +'=:"' + fields[x].FieldName + '",';
         sql_set := sql_set +FieldNamesQuoteChars[0] + fields[x].FieldName + FieldNamesQuoteChars[1] +'=:"' + fields[x].FieldName + '",';
       end;
       end;
 
 
@@ -1656,7 +1656,7 @@ var FieldNamesQuoteChars : TQuoteChars;
     sql_values := '';
     sql_values := '';
     for x := 0 to Fields.Count -1 do
     for x := 0 to Fields.Count -1 do
       begin
       begin
-      if (not fields[x].IsNull) and (pfInUpdate in Fields[x].ProviderFlags) then
+      if (not Fields[x].IsNull) and (pfInUpdate in Fields[x].ProviderFlags) and (not Fields[x].ReadOnly) then
         begin
         begin
         sql_fields := sql_fields + FieldNamesQuoteChars[0] + fields[x].FieldName + FieldNamesQuoteChars[1] + ',';
         sql_fields := sql_fields + FieldNamesQuoteChars[0] + fields[x].FieldName + FieldNamesQuoteChars[1] + ',';
         sql_values := sql_values + ':"' + fields[x].FieldName + '",';
         sql_values := sql_values + ':"' + fields[x].FieldName + '",';