View Issue Details

IDProjectCategoryView StatusLast Update
0004935JEDI VCL00 JVCL Componentspublic2009-09-14 20:48
ReporterJeremyKnowlesAssigned ToAHUser 
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
Product Version3.37 
Target VersionFixed in Version3.39 
Summary0004935: CSVDataset error (actually v 3.38)
DescriptionUsing TJvCustomCsvDataSet (TJvCsvDataSet component) and opening a bad file doesn't then allow a good file to be opened afterwards. This is because it keeps the header row from the bad file. This in turn is because FCsvFileLoaded is still set to true even though the bad file couldn't load so next time, when you try to load a good file, ReadCsvFileStream doesn't happen so the header row is still set to the previous (bad) file. I found this by trying to import a file with no header.

The fix is quite straightforward. Add a try/except around TJvCustomCsvDataSet.InternalOpen and set FCsvFileLoaded := false; if there is an exception. The entire routine becomes:

procedure TJvCustomCsvDataSet.InternalOpen;
var
  AppendStr: string;
  CsvLine: RawByteString;
  Counter: Integer;
  csvFileExists: Boolean;
begin
  if FCursorOpen then
    InternalClose; // close first!
  try
    Counter := 0;

    FFileDirty := False;
    if FLoadsFromFile then
    begin
      if FTableName = '' then
        JvCsvDatabaseError(RsENoTableName, RsETableNameRequired);

      FOpenFileName := GetFileName; // Always use the same file name to save as you did to load!!! MARCH 2004.WP
    end
    else
    begin
      FOpenFileName := '';
    end;

    InternalInitFieldDefs; // initialize FieldDef objects.

      // Create TField components when no persistent fields have been created
    if DefaultFields then
      CreateFields;
    BindFields(True); // bind FieldDefs to actual Data

    if FCsvColumns.Count > 1 then
    begin
      // Create a null terminated string which is just a bunch of commas:
      SetLength(FEmptyRowStr, FCsvColumns.Count - 1);
      // When adding an empty row, we add this string as the ascii equivalent:
      FillNativeChar(FEmptyRowStr[1], FCsvColumns.Count - 1, Separator);
    end
    else
      FEmptyRowStr := ''; // nothing.

    FRecordPos := JvCsv_ON_BOF_CRACK; // initial record pos before BOF
    BookmarkSize := SizeOf(Integer);
    // initialize bookmark size for VCL (Integer uses 4 bytes on 32 bit operating systems)

    csvFileExists:= False;
    if FLoadsFromFile then // ReadCsvFileStream:Creates file stream and start reading it. Sets FCsvFileTopLine.
      csvFileExists := ReadCsvFileStream;

    if FHasHeaderRow then
    begin
      if csvFileExists and not ExtendedHeaderInfo and (FCsvFileTopLine <> '') then
        FHeaderRow := FCsvFileTopLine
      else
      begin
        FHeaderRow := GetColumnsAsString; // creating a new file! set up HeaderRow
        FCsvFileTopLine := FHeaderRow;
      end;

      if FHeaderRow <> '' then
        try
          ProcessCsvHeaderRow;
        except
          FHeaderRow := '';
          FreeAndNil(FCsvStream);
          raise;
        end;

      if FAppendedFieldCount > 0 then
      begin
        SetLength(AppendStr, FAppendedFieldCount);
        FillNativeChar(AppendStr[1], FAppendedFieldCount, Separator);
      end;
    end;

    // Load rows from disk to memory, using Stream object to read line by line.
    if FLoadsFromFile and Assigned(FCsvStream) then
    begin
      while not FCsvStream.Eof do
      begin
        CsvLine := JvTrimAnsiStringCrLf(FCsvStream.ReadLine);// leading space, trailing space and crlf are removed by Trim!
        if CsvLine <> '' then
        begin
          if (FSpecialDataMarker <> '')
            and (Pos(FSpecialDataMarker, CsvLine) = 1)
            and Assigned(FOnSpecialData) then
          begin
            // This very rarely used feature should
            // probably be removed from the JVCL? -WPostma.
            FOnSpecialData(Self, Counter, CsvLine);
          end
          else
          begin
            // Process the row:
            {$IFDEF UNICODE}
            if FUtf8Detected then
              ProcessCsvDataRow(Utf8ToAnsi(CsvLine), Counter)
            else
            {$ENDIF UNICODE}
              ProcessCsvDataRow(string(AnsiString(CsvLine)), Counter);
            Inc(Counter);
          end;
        end;
      end; {while}
    end;{if}
    if Active then
      First;
    FCursorOpen := True;
  except
    FCsvFileLoaded := false;
    Raise;
  end;
  { clean up stream object }
  FreeAndNil(FCsvStream);
end;
TagsNo tags attached.

Relationships

related to 0004901 resolvedAHUser [TJvCsvDataSet] loading successively different csv files in a same TJvCsvDataSet fires un unexpected exception 

Activities

JeremyKnowles

2009-09-14 12:23

reporter   ~0016097

I just noticed 0004901, but that fix didn't solve it in my instance (where there is no header or you try to import something obscure like a jpeg).

AHUser

2009-09-14 20:48

developer   ~0016099

Patch applied to SVN. Thanks.

Issue History

Date Modified Username Field Change
2009-09-14 12:15 JeremyKnowles New Issue
2009-09-14 12:23 JeremyKnowles Note Added: 0016097
2009-09-14 14:01 obones Relationship added related to 0004901
2009-09-14 14:02 obones Status new => acknowledged
2009-09-14 20:48 AHUser Note Added: 0016099
2009-09-14 20:48 AHUser Status acknowledged => resolved
2009-09-14 20:48 AHUser Fixed in Version => Daily / SVN
2009-09-14 20:48 AHUser Resolution open => fixed
2009-09-14 20:48 AHUser Assigned To => AHUser