Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2013.03.22;
Скачать: CL | DM;

Вниз

ADO + Ora = пропихнуть в хранимку blob более 32 кбайт   Найти похожие ветки 

 
Es   (2012-08-16 16:02) [0]

Имеется хранимка на сервере Oracle, один из входящих параметров blob:

...
i_FILE_BODY in blob,
...


Имеем TAdoConnection и TADOStoredProc, натравленный на хранимку.
Тип параметра указан как ftBlob. Грузится как [AddParam].LoadFromStream(..., ftBlob)

При execute получаем ошибку:

ORA-01460: затребовано нереализованное или неразумное преобразование
http://www.onlinedisk.ru/get_image.php?id=928134

Что за фигня с ADO? Что он такого делает, что потом ругается ОРАКЛ со СВОЕЙ стороны?

Эксперименты показали, что если сформировать большой блоб на стороне сервера (мегабайт на 15) и запихнуть его в хранимку - то все здорово и беспроблемно. Но если с дельфового клиенту через ADO указанным выше способом - то облом.

Провайдер используется родной: OraOLEDB.Oracle.1 (так как в MS"ном вообще blob не поддерживается).
Клиент Win 7, ора 11g на nix.

Кто-нибудь сталкивался еще с таким бредом?


 
AV ©   (2012-08-16 16:16) [1]

ага,
переделал через query

 oqTmp.sql.text := "Update SUBSCRIBER set PIC=EMPTY_BLOB() Where ID_SUBSCRIBER = :ID_SUBSCRIBER RETURNING PIC INTO :PIC";
 oqTmp.ParamByName("PIC").ParamType := ptInput;
 oqTmp.ParamByName("PIC").DataType := ftOraBlob;
 oqTmp.ParamByName("PIC").AsBLOBLocator.LoadFromFile(dlgOpenPic.FileName);
 oqTmp.ParamByName("ID_SUBSCRIBER").asinteger := FSubscriber;
 oqTmp.ExecSQL;


 
QAZ   (2012-08-16 16:41) [2]

а зачем человеки вообще пихают в базы всякие блобы с картинками ?
почему их не хранить файлами а в базе хранить адрес?


 
DVM ©   (2012-08-16 16:43) [3]


> QAZ   (16.08.12 16:41) [2]
> а зачем человеки вообще пихают в базы всякие блобы с картинками
> ?
> почему их не хранить файлами а в базе хранить адрес?

удобно потому что


 
AV ©   (2012-08-16 16:43) [4]


> QAZ   (16.08.12 16:41) [2]

Все в одном, ничего не потеряется
или потеряется все :)


 
имя   (2012-08-16 16:46) [5]

Удалено модератором


 
QAZ   (2012-08-16 16:47) [6]

а резервировать и тд?


 
DVM ©   (2012-08-16 16:47) [7]


> AV ©   (16.08.12 16:43) [4]

Да кроме этого причин хранить бинарные данные в базе масса, а вот причин не хранить и хранить в файлах я не знаю ни одной.


 
DVM ©   (2012-08-16 16:50) [8]

Удалено модератором


 
QAZ   (2012-08-16 16:51) [9]


> DVM ©   (16.08.12 16:47) [7]

ну наверно в базе нужно хранить то что можно искать,сортировать, это ведь основная идея существования баз данных?
а картинку то зачем мучить?


 
Es   (2012-08-16 16:55) [10]

Так никто в проблема не разбирался? Что за нафиг делает ADO с блобом при передачи, что у Оры крышу рвет?


 
DVM ©   (2012-08-16 16:55) [11]


>  QAZ  

Из прочих плюсов

1. Разграничение прав на уровне базы.
2. Гораздо легче открыть 1 порт для подключения к базе через интернет, чем городить доступ к файловому серверу и еще как то связывать пути на нем с записями в базе.
3. При хранении файлов отдельно от базы надо заботиться о том, чтобы ссылки всегда были верными и что делать при удалении файла?

Вообще на ibase.ru была статья для опасающихся хранить файлы в базе от создателей Firebird.


 
QAZ   (2012-08-16 16:56) [12]

Удалено модератором


 
AV ©   (2012-08-16 16:57) [13]


> Что за нафиг делает ADO с блобом при передачи, что у Оры
> крышу рвет?

Есть подозрение, что как -то не так размер передается
Но не разбирался до конца, тупо стал грузить запросом


 
Sergey Masloff   (2012-08-16 16:59) [14]

QAZ   (16.08.12 16:51) [9]
>ну наверно в базе нужно хранить то что можно искать,сортировать, это >ведь основная идея существования баз данных?
>а картинку то зачем мучить?
Не надо свое видение обобщать. Я лично из своего опыта согласен с DVM (с) и не вижу ни одной причины хнанить связанные данные в разных местах.

DVM ©   (16.08.12 16:50) [8]
>База же ограничена лишь размером максимального файла в фс.
И даже этим не ограничена.


 
Sergey Masloff   (2012-08-16 17:02) [15]

QAZ   (16.08.12 16:56) [12]
>нену как сорганизуеш,сдается мне что отображение картинки не самое >важное,и можно потерпеть загрузку при запросе
>даи всякие фрагментации баз за щет ненужной инфы тоже не убыстрят >процесс
Извини но ЯХДР от этого потока сознания ;-)
- что такое "потерять загрузку при запросе"
- про фрагментацию баз вообще достаточно смешно.


 
DVM ©   (2012-08-16 17:03) [16]


> QAZ   (16.08.12 16:56) [12]


> даи всякие фрагментации баз за щет ненужной инфы тоже не
> убыстрят процесс

Информация в файле базы записывается постранично, при удалении страницы помечаются как свободные, файл базы на диске как правило не уменьшается никогда сам пос себе, может только расти. Т.е фактически запись в базу - это просто запись в файл на диск в свободные страницы. Это по скорости примерно тоже самое что прямо писать в файл. Чуть-чуть медленнее, но самым медленным звеном тут всегда будет диск и сеть, а не сервер баз данных и какие то дополнительные обработки.


 
QAZ   (2012-08-16 17:07) [17]

Удалено модератором


 
DVM ©   (2012-08-16 17:12) [18]


> QAZ   (16.08.12 17:07) [17]
> нуи нахрена нужен файл где половина размера есть неиспользуемое
> место после удалений записей ?

Плата за удобство.

Есть правда один вариант, который я допускаю, но особенно хорошим его все же не считаю. Во многих СУБД можно сделать так (в Firebird например за счет написания своих расширений - udf), чтобы при загрузке файла на сервер баз данных он сохранялся не в базе а рядом с ней в файловой системе. И читался из файловой системы при попытке чтения из базы. Т.е к файлам в файловой системе доступ будет иметь только сервер субд, но прямого доступа извне к ним нет. Но у этого способа есть куча недостатков и они перевешивают единственное "достоинство" - файлы не лежат в базе.


 
QAZ   (2012-08-16 17:14) [19]


> Но у этого способа есть куча недостатков

какие


 
DVM ©   (2012-08-16 17:15) [20]


> QAZ   (16.08.12 17:07) [17]
> нуи нахрена нужен файл где половина размера есть неиспользуемое
> место после удалений записей ?

Это решаемо кстати на NTFS. Там есть понятие разреженные файлы - файлы которые имеют размер больше чем реально на диске занимают.


 
AV ©   (2012-08-16 17:17) [21]

имхо, все равно, наверное почти все субд, "форматируют" отведенное им место под себя и пишут данные блоками. Предпочтительно, кратными ФС.
Так что не особо "дырки" будут мешать


 
QAZ   (2012-08-16 17:17) [22]


> DVM ©   (16.08.12 17:15) [20]

врятли, ведь запись при удалении не зануляется


 
DVM ©   (2012-08-16 17:20) [23]


> QAZ   (16.08.12 17:17) [22]


> врятли, ведь запись при удалении не зануляется

Ее не надо занулять, достаточно сказать системе, что место от сих до сих (смещение в файле) не используется. Драйвер сам разберется что кому и куда. Я не знаю, использует ли эту возможность хоть одна из существующих субд.


 
QAZ   (2012-08-16 17:24) [24]

Удалено модератором


 
QAZ   (2012-08-16 17:26) [25]

чувствую что надо изобрести свою СУБД для ленивых батонокидателей дабы спасти,а потом поработить мир


 
DVM ©   (2012-08-16 17:26) [26]


> QAZ   (16.08.12 17:24) [24]


> далан, и какой функцией?

DeviceIoControl


 
DVM ©   (2012-08-16 17:27) [27]


> QAZ


////////////////////////////////////////////////////////////////////////////////
//
//  ****************************************************************************
//  * Модуль       : uNTFSFileStream.pas
//  * Назначение   : Класс файлового потока, реализующий доп. возможности NTFS
//  * Copyright    : 2012 © Дмитрий Муратов (dvmuratov@yandex.ru)
//  * Версия       : 1.0
//  * Дата         : 06.02.2012
//  ****************************************************************************
//
////////////////////////////////////////////////////////////////////////////////

unit uNTFSFileStream;

interface

{$I DEFINES.INC}

{$IFNDEF MSWINDOWS}
These streams are only usable in Windows!!!
{$ENDIF}

{$WARN SYMBOL_PLATFORM OFF}

uses
{$IFDEF DELPHIXE2_UP}
 Winapi.Windows, System.SysUtils, System.Classes;
{$ELSE}
 Windows, SysUtils, Classes;
{$ENDIF}

type
 TNTFSFileStreamOption = (fsoCompressed, fsoSparse, fsoTemporary, fsoEncrypted,
   fsoWriteThrough, fsoNoBuffering, fsoRandomAccess, fsoSequentialScan,
   fsoDeleteOnClose);

 TNTFSFileStreamOptions = set of TNTFSFileStreamOption;

 TNTFSFileStream = class(THandleStream)
 strict private
   FFileName: string;
   FMode: Word;
   FOptions: TNTFSFileStreamOptions;
   procedure SetCompression(const AHandle: THandle; const AEnabled: Boolean);
   procedure SetSparse(const AHandle: THandle);
   function CreateFile(const AFilename: string; const AMode: Word;
     const AOptions: TNTFSFileStreamOptions = []): THandle;
   function GetCompressed: Boolean;
   procedure SetCompressed(const AValue: Boolean);
 public
   constructor Create(const AFilename: string; const AMode: Word = fmCreate;
     const AOptions: TNTFSFileStreamOptions = []);
   destructor Destroy; override;
   procedure ZeroData(const AFileOffset: Int64 = 0; const ALength: Int64 = 0);
   procedure ZeroDataForTwoOffsets(const AFirstOffset, ALastOffset: Int64);
   procedure ZeroToCurrPosition;
   property Compressed: Boolean read GetCompressed write SetCompressed;
   procedure Recompress;
   procedure Decompress;
   procedure Compress;
   property FileName: string read FFileName;
   property Mode: Word read FMode;
   property Options: TNTFSFileStreamOptions read FOptions;
 end;



 
DVM ©   (2012-08-16 17:28) [28]


implementation

resourcestring
 rsCanNotEncryptFiles = "Can not encrypt files on a non-NT platform";
 rsFileIsNotSparse = "File "%s" is not sparse";

type
 TEncryptFile = function(lpFilename: PChar): BOOL; stdcall;

type
 TFileZeroDataInformation = record
   FileOffset: Int64;
   BeyondFinalZero: Int64;
 end;
 PFileZeroDataInformation = ^TFileZeroDataInformation;

var
 EncryptFile: TEncryptFile;

const
 FILE_ATTRIBUTE_SPARSE_FILE  = $80;
 FSCTL_GET_COMPRESSION       = $9003C;
 FSCTL_SET_COMPRESSION       = $9C040;
 FSCTL_SET_ZERO_DATA         = $980C8;
 FSCTL_SET_SPARSE            = $900C4;

 COMPRESSION_FORMAT_NONE     = 0;
 COMPRESSION_FORMAT_DEFAULT  = 1;

{ TNTFSFileStream }

procedure TNTFSFileStream.Compress;
begin
 Compressed := True;
end;

//------------------------------------------------------------------------------

constructor TNTFSFileStream.Create(const AFilename: string;
 const AMode: Word = fmCreate; const AOptions: TNTFSFileStreamOptions = []);
begin
 FFileName := AFilename;
 FMode := AMode;
 FOptions := AOptions;
 inherited Create(CreateFile(FFilename, FMode, FOptions));
end;

//------------------------------------------------------------------------------

function TNTFSFileStream.CreateFile(const AFilename: string;
 const AMode: Word; const AOptions: TNTFSFileStreamOptions): THandle;
var
 DesiredAccess: Cardinal;
 ShareMode: Cardinal;
 CreationDisposition: Cardinal;
 FlagsAndAttributes: Cardinal;
 Option: TNTFSFileStreamOption;
begin
 DesiredAccess := 0;
 ShareMode := 0;
 if (AMode and fmCreate) = fmCreate then
   begin
     if FileExists(AFilename) then
       if not DeleteFile(AFilename) then
         RaiseLastOSError;

     DesiredAccess := GENERIC_READ or GENERIC_WRITE;
     ShareMode := 0;
     CreationDisposition := CREATE_ALWAYS;

     FlagsAndAttributes := FILE_ATTRIBUTE_NORMAL;
     for Option := Low(TNTFSFileStreamOption) to High(TNTFSFileStreamOption) do
       if Option in AOptions then
         case Option of
           fsoTemporary: FlagsAndAttributes := FlagsAndAttributes or FILE_ATTRIBUTE_TEMPORARY;
           fsoWriteThrough: FlagsAndAttributes := FlagsAndAttributes or FILE_FLAG_WRITE_THROUGH;
           fsoNoBuffering: FlagsAndAttributes := FlagsAndAttributes or FILE_FLAG_NO_BUFFERING;
           fsoRandomAccess: FlagsAndAttributes := FlagsAndAttributes or FILE_FLAG_RANDOM_ACCESS;
           fsoSequentialScan: FlagsAndAttributes := FlagsAndAttributes or FILE_FLAG_SEQUENTIAL_SCAN;
           fsoDeleteOnClose: FlagsAndAttributes := FlagsAndAttributes or FILE_FLAG_DELETE_ON_CLOSE;
         end;
   end
 else
   begin
     FlagsAndAttributes := FILE_ATTRIBUTE_NORMAL;
     case AMode and 3 of
       fmOpenRead: DesiredAccess := GENERIC_READ;
       fmOpenWrite: DesiredAccess := GENERIC_WRITE;
       fmOpenReadWrite: DesiredAccess := GENERIC_READ or GENERIC_WRITE;
       fmOpenReadWrite or fmOpenWrite: DesiredAccess := GENERIC_READ or GENERIC_WRITE;
     end;
     case AMode and $F0 of
       fmShareCompat, fmShareExclusive: DesiredAccess := DesiredAccess or 0;
       fmShareDenyWrite: DesiredAccess := DesiredAccess or FILE_SHARE_READ;
       fmShareDenyRead: DesiredAccess := DesiredAccess or FILE_SHARE_WRITE;
       fmShareDenyNone: DesiredAccess := DesiredAccess or (FILE_SHARE_READ or FILE_SHARE_WRITE);
     end;
     CreationDisposition := OPEN_EXISTING;
   end;

 {$IFDEF DELPHIXE2_UP}
 Result := Winapi.Windows.CreateFile(PChar(Filename), DesiredAccess,
   ShareMode, nil, CreationDisposition, FlagsAndAttributes, 0);
 {$ELSE}
 Result := Windows.CreateFile(PChar(AFilename), DesiredAccess, ShareMode,
   nil, CreationDisposition, FlagsAndAttributes, 0);
 {$ENDIF}

 if Result = INVALID_HANDLE_VALUE then
   RaiseLastOSError;

 try
   if (AMode and fmCreate) = fmCreate then
   begin
     if fsoEncrypted in AOptions then
       begin
         CloseHandle(Result);
         if not Assigned(EncryptFile) then
           raise Exception.Create(rsCanNotEncryptFiles);
         if not EncryptFile(PChar(AFilename)) then
           RaiseLastOSError;
         Result := CreateFile(AFilename, fmOpenReadWrite or fmShareExclusive, AOptions);
       end
     else
       SetCompression(Result, fsoCompressed in AOptions);
   end;

   if fsoSparse in AOptions then
     SetSparse(Result);

 except
   CloseHandle(Result);
   raise;
 end;
end;


 
DVM ©   (2012-08-16 17:28) [29]


//------------------------------------------------------------------------------

procedure TNTFSFileStream.Decompress;
begin
 Compressed := False;
end;

//------------------------------------------------------------------------------

destructor TNTFSFileStream.Destroy;
begin
 if Handle <> 0 then
   CloseHandle(Handle);
 inherited;
end;

//------------------------------------------------------------------------------

function TNTFSFileStream.GetCompressed: Boolean;
var
 CompressionAlgorithm: Word;
 Dummy: Cardinal;
begin
 if not DeviceIoControl(Handle, FSCTL_GET_COMPRESSION, nil, 0,
   @CompressionAlgorithm, SizeOf(CompressionAlgorithm), Dummy, nil) then
   RaiseLastOSError;
 Result := (CompressionAlgorithm <> COMPRESSION_FORMAT_NONE);
end;

//------------------------------------------------------------------------------

procedure TNTFSFileStream.Recompress;
begin
 if Compressed then
   begin
     Decompress;
     Compress;
   end;
end;

//------------------------------------------------------------------------------

procedure TNTFSFileStream.SetCompressed(const AValue: Boolean);
begin
 if AValue <> GetCompressed then
   SetCompression(Handle, AValue);
end;

//------------------------------------------------------------------------------

procedure TNTFSFileStream.SetCompression(const AHandle: THandle;
 const AEnabled: Boolean);
var
 Dummy                 : Cardinal;
 CompressionAlgorithm  : Word;
const
 CompressionAlgorithms : array[Boolean] of Word = (
   COMPRESSION_FORMAT_NONE,
   COMPRESSION_FORMAT_DEFAULT
 );
begin
 CompressionAlgorithm := CompressionAlgorithms[AEnabled];
 if not DeviceIoControl(AHandle, FSCTL_SET_COMPRESSION, @CompressionAlgorithm,
   SizeOf(CompressionAlgorithm), nil, 0, Dummy, nil) then
   RaiseLastOSError;
end;

//------------------------------------------------------------------------------

procedure TNTFSFileStream.SetSparse(const AHandle: THandle);
var
 Dummy : Cardinal;
begin
 if not DeviceIoControl(AHandle, FSCTL_SET_SPARSE, nil, 0, nil, 0, Dummy, nil) then
   RaiseLastOSError;
end;

//------------------------------------------------------------------------------

procedure TNTFSFileStream.ZeroData(const AFileOffset, ALength: Int64);
begin
 ZeroDataForTwoOffsets(AFileOffset, AFileOffset + ALength);
end;

//------------------------------------------------------------------------------

procedure TNTFSFileStream.ZeroDataForTwoOffsets(const AFirstOffset, ALastOffset: Int64);
var
 FileZeroDataInformation: TFileZeroDataInformation;
 BytesReturned: Cardinal;
begin
 if not (fsoSparse in FOptions) then
   raise Exception.CreateFmt(rsFileIsNotSparse, [FFileName]);
 FileZeroDataInformation.FileOffset := AFirstOffset;
 FileZeroDataInformation.BeyondFinalZero := ALastOffset;
 if not DeviceIoControl(Handle, FSCTL_SET_ZERO_DATA, @FileZeroDataInformation,
   SizeOf(FileZeroDataInformation), nil, 0, BytesReturned, nil) then
   RaiseLastOSError;
end;

//------------------------------------------------------------------------------

procedure TNTFSFileStream.ZeroToCurrPosition;
begin
 ZeroDataForTwoOffsets(0, Position);
end;

//------------------------------------------------------------------------------

var
 ADVAPI32Handle  : THandle;

initialization

 EncryptFile := nil;

 ADVAPI32Handle := LoadLibrary("advapi32.dll");
 if ADVAPI32Handle <> 0 then
   {$IFDEF UNICODE}
   EncryptFile := GetProcAddress(ADVAPI32Handle, "EncryptFileW");
   {$ELSE}
   EncryptFile := GetProcAddress(ADVAPI32Handle, "EncryptFileA");
   {$ENDIF}

finalization

 FreeLibrary(ADVAPI32Handle);
 EncryptFile := nil;

end.



 
имя   (2012-08-16 17:32) [30]

Удалено модератором


 
имя   (2012-08-16 17:35) [31]

Удалено модератором


 
DVM ©   (2012-08-16 17:36) [32]


> QAZ   (16.08.12 17:32) [30]


> одно дело сказать что файл спарседный, а другое дело указать
> место

Смещения можно указать в разреженном файле всегда и какие угодно. Все что между ними будет исключено из файла и места занимать не будет на диске. В чем проблема то?


 
QAZ   (2012-08-16 17:42) [33]


> В чем проблема то?

да все норм,показалось


 
Es   (2012-08-16 19:18) [34]


> согласен с DVM (с) и не вижу ни одной причины хнанить связанные
> данные в разных местах.

Серег, ну вообще в контексте WEB есть одна причина и имя ей - HTTP-протокол, ибо он запрос-ответ ориентированный. Браузер грузит страницу - а там HTTP-ссылки на 20 изображений. Он генерирует еще 20 запросов на получение этих 20 картинок. Самое наглядное, когда используется распространенный вариант front в виде nginx для быстрой отдачи статики, а за ним back в виде apache для обработки динамики.

1) обработка статики:

Клиент / Браузер -> GET/ -> Nginx -> Файловая система, считывание файла и отдача

2) обработка динамики

Клиент / Браузер -> GET/ -> Nginx -> Apache -> PHP -> Database -> blablabla...

В случае хранения картинок в БД первый вариант обработки исключен, а это ооочень сильно снижает быстродействие и не позволяет пользоваться уже считай стандартизированными решениями. Ибо nginx безумно быстро умеет отдавать статический файл с диска, не нагружая Apache инициализацией подключения. Специфика, но очень распространенная, отсюда большая привычка многих начинающих с программирования под веб хранить файлы на диске, а не в БД.

Что в "классическом" программировании вызывает непонимание, тем более это плохо реализуется, по крайней мере при двухзвенной структуре.


 
MsGuns ©   (2012-08-17 11:39) [35]

Аргументы против файл-серверов:
1) Реляционность. Во многих нормальных КС в базе хранятся не только данные, но и масса непосрественно софта: шаблоны, отчеты, визуальные элементы интерфейса (формы, фрэймы, диалоги, стили и т.д.). Если все это вынести в файлы, получится туча разнокалиберных файлов со сложной системой привязки к собственно логическим объектам модели БД. В самой же базе все связи прекрасно представлены средствами сервера (бизнес-логика).
2) Целостность. Если часть данных модели раположена вне самой БД, то на порядки возрастает сложность ПО по поддержке целостности данных. "Вшивать" в триггеры обращение к внешним файлам - это что-то, да и не всякий скл-сервер позволяет. И что делать с транзакционностью ?
Про бэкапы и ресторы вообще умолчу.
3) Масштабируемость. При резком повышении интенсивности работы (в т.ч. на запись) в файл-серверном варианте обеспечены длительные ожидания и даже зависания, управлять которыми фактически нет возможности. При серверном решении такие возможности имеются, и весьма в ассортименте.
4) Конфеденциальность. Тут все ясно без слов.

Хватит ?


 
Es   (2012-08-17 12:05) [36]

Удалено модератором


 
QAZ   (2012-08-17 13:13) [37]

а мне кажеца или на серверах где крутятся сотни сайтов и форумов с милиардами файлов, кучей запросов и прочей белеберды, все както работает, с масштабируемостью, конфиденциальностью, бэкапами и тд ?


 
AV ©   (2012-08-17 13:20) [38]


> QAZ   (17.08.12 13:13) [37]

Разумно..
Но есть подозрение, что это все опять виртуально
Сайт - файл. Внутри твои картинки, скрипты, др. А снаружи это один файл.
У нас так сайт сделан. На одном из серверов виртуалка стоит, бэкап сайта - бэкап файла виртуалки :)


 
Sergey Masloff   (2012-08-17 13:21) [39]

QAZ   (17.08.12 13:13) [37]
Кажется


 
QAZ   (2012-08-17 13:27) [40]


> AV ©   (17.08.12 13:20) [38]

кая разница что это снаружи один файл когда внутри тот же милион, да и виртуализация не прибавляет скорости



Страницы: 1 2 вся ветка

Текущий архив: 2013.03.22;
Скачать: CL | DM;

Наверх




Память: 0.6 MB
Время: 0.107 c
15-1333730960
Дмитрий С
2012-04-06 20:49
2013.03.22
Очень сильно тупит delphiXE


15-1351492587
Olga.Duplenko
2012-10-29 10:36
2013.03.22
Работа для классных профессионалов-разработчиков


15-1334133391
ПЛОВ
2012-04-11 12:36
2013.03.22
вопрос по TListView


15-1349860163
Sinister
2012-10-10 13:09
2013.03.22
MacBook Pro


15-1336126916
AV
2012-05-04 14:21
2013.03.22
Можно ли вернуть билет в кинотеатре, т.к. фильм не нравится?