IsNull возвращает TRUE при вставке пустых (НЕ NULL) строк в поле LONG VARCHAR (SQL Anywhere) - PullRequest
0 голосов
/ 02 октября 2019

Delphi 10.3.2 предприятие, база данных ASA (SQL Anywhere 17.0.9.4913).

У меня есть эта таблица

CREATE TABLE string_null(
    lo_key integer NOT NULL DEFAULT AUTOINCREMENT PRIMARY KEY,
    str_short char(100) NOT NULL DEFAULT '',
    str_long long varchar NOT NULL DEFAULT '');

, и я хочу вставить записи, используя FireDAC TFDConnection иTFDQuery компоненты.

qry.Insert;

Если я назначаю непустые строки, все работает правильно.

qry.FindField('str_short').Asstring := 'ABC';
qry.FindField('str_long').Asstring := 'XYZ';

Если я вставляю запись, используя пустые строки (пусто, не ноль!)

qry.FindField('str_short').Asstring := '';  // IsNull is FALSE, ok
qry.FindField('str_long').Asstring := '';   // IsNull becomes TRUE (wrong!)

свойство IsNull в поле LONG VARCHAR возвращает TRUE, даже если ему было присвоено значение NOT NULL (пустая строка), а короткое поле поведение правильное.

( Свойство FormatOptions.StrsEmpty2Null как для соединения, так и для запроса равно FALSE ).

Кроме того, когда я выполняю Post() метод, Delphi вызывает исключение для поля LONG VARCHAR:

Поле 'str_long' должно иметь значение

Если я установил

qry.FindField('str_long').Required := FALSE;
qry.Post;

запись успешно вставлена ​​в базу данных со значениями пустых строк.

Короче говоря, длинная история: если я вставлюТ.е. запись с пустыми строковыми значениями в поле LONG VARCHAR, свойство IsNull возвращает неправильное значение, и мне нужно присвоить Required := False, чтобы выполнить операцию INSERT.

В этом небольшом демонстрационном приложении я пытаюсь вставить

  • запись со строками NOT EMPTY (и все работает правильно)

  • запись со строками EMPTY.

Test application output

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf,
  FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Phys.ASA, FireDAC.Phys.ASADef, FireDAC.VCLUI.Wait,
  FireDAC.Stan.Param, FireDAC.DatS, FireDAC.DApt.Intf, FireDAC.DApt, Data.DB, FireDAC.Comp.DataSet, FireDAC.Comp.Client, Vcl.StdCtrls,
  FireDAC.Phys.SQLite, FireDAC.Phys.SQLiteDef, FireDAC.Stan.ExprFuncs, FireDAC.Phys.ODBCBase, FireDAC.Comp.UI;

type
  TForm1 = class(TForm)
    conn: TFDConnection;
    qry: TFDQuery;
    memo: TMemo;
    procedure FormCreate(Sender: TObject);
  private
    procedure exec_insert(str_value : string);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

const
  LONG_FIELD = 'str_long';
  SHORT_FIELD = 'str_short';

procedure TForm1.exec_insert(str_value : string);

  procedure msg(s : string);
  begin
    memo.Text := memo.Text + s + #13#10
  end;

begin
  msg('======================');
  msg('INSERT VALUE = "' + str_value + '"');
  try
    qry.Insert;

    if qry.FindField(SHORT_FIELD).IsNull then msg('BEFORE assign SHORT field is NULL')
    else msg('BEFORE assign SHORT field is NOT NULL');
    if qry.FindField(LONG_FIELD).IsNull then msg('BEFORE assign LONG field is NULL')
    else msg('BEFORE assign LONG field is NOT NULL');
    msg('');

    qry.FindField(SHORT_FIELD).AsString := str_value;
    qry.FindField(LONG_FIELD).Asstring := str_value;

    if qry.FindField(SHORT_FIELD).IsNull then msg('AFTER assign SHORT field is NULL')
    else msg('AFTER assign SHORT field is NOT NULL');
    if qry.FindField(LONG_FIELD).IsNull then msg('AFTER assign LONG field is NULL')
    else msg('AFTER assign LONG field is NOT NULL');

    //qry.FindField(LONG_FIELD).Required := FALSE;
    qry.Post
  except
    on e: Exception do msg('EXCEPTION: ' + e.message)
  end;
  msg('')
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  s : string;
begin
  conn.params.Text := 'Database=jolly'#$D#$A'User_Name=jop'#$D#$A'Password=jpw'#$D#$A'Server=jolly'#$D#$A'DriverID=ASA'#$D#$A;
  conn.FormatOptions.StrsEmpty2Null := FALSE;
  conn.Connected := TRUE;

  qry.FormatOptions.StrsEmpty2Null := FALSE;
  qry.SQL.Text := 'select * from string_null';
  qry.UpdateOptions.RequestLive := TRUE;
  qry.Active := TRUE;

  exec_insert('ABC');
  exec_insert('')
end;

end.
object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 299
  ClientWidth = 635
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  DesignSize = (
    635
    299)
  PixelsPerInch = 96
  TextHeight = 13
  object memo: TMemo
    Left = 120
    Top = 8
    Width = 273
    Height = 283
    Anchors = [akLeft, akTop, akBottom]
    TabOrder = 0
  end
  object conn: TFDConnection
    Left = 28
    Top = 12
  end
  object qry: TFDQuery
    Connection = conn
    Left = 28
    Top = 64
  end
end
program Project1;

uses
  Vcl.Forms,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

Я не тестировал поведение с другими базами данных.

...