From bf5ba60b07980c1d56c49c61b46154605a913235 Mon Sep 17 00:00:00 2001 From: Mirko Viviani Date: Fri, 15 Nov 2002 22:57:05 +0000 Subject: [PATCH] *** empty log message *** git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gdl2/trunk@14993 72102866-910b-0410-8b05-ffd578937521 --- AUTHORS | 4 + COPYING.LIB | 481 ++ ChangeLog | 751 ++ EOAccess/EOAccess.h | 73 + EOAccess/EOAccessFault.h | 114 + EOAccess/EOAccessFault.m | 324 + EOAccess/EOAccessFaultPriv.h | 37 + EOAccess/EOAdaptor.h | 172 + EOAccess/EOAdaptor.m | 719 ++ EOAccess/EOAdaptorChannel.h | 233 + EOAccess/EOAdaptorChannel.m | 609 ++ EOAccess/EOAdaptorContext.h | 135 + EOAccess/EOAdaptorContext.m | 277 + EOAccess/EOAdaptorOperation.m | 215 + EOAccess/EOAdaptorPriv.h | 40 + EOAccess/EOAttribute.h | 282 + EOAccess/EOAttribute.m | 1285 ++++ EOAccess/EOAttributePriv.h | 50 + EOAccess/EODatabase.h | 113 + EOAccess/EODatabase.m | 617 ++ EOAccess/EODatabaseChannel.h | 92 + EOAccess/EODatabaseChannel.m | 792 ++ EOAccess/EODatabaseChannelPriv.h | 48 + EOAccess/EODatabaseContext.h | 432 ++ EOAccess/EODatabaseContext.m | 6670 +++++++++++++++++ EOAccess/EODatabaseContextPriv.h | 70 + EOAccess/EODatabaseDataSource.h | 67 + EOAccess/EODatabaseDataSource.m | 418 ++ EOAccess/EODatabaseOperation.h | 180 + EOAccess/EODatabaseOperation.m | 351 + EOAccess/EODatabaseOperationPriv.h | 37 + EOAccess/EOEntity.h | 373 + EOAccess/EOEntity.m | 4367 +++++++++++ EOAccess/EOEntityPriv.h | 68 + EOAccess/EOExpressionArray.h | 107 + EOAccess/EOExpressionArray.m | 400 + EOAccess/EOJoin.h | 70 + EOAccess/EOJoin.m | 202 + EOAccess/EOModel.h | 191 + EOAccess/EOModel.m | 1608 ++++ EOAccess/EOModelGroup.h | 137 + EOAccess/EOModelGroup.m | 403 + EOAccess/EOPropertyListEncoding.h | 43 + EOAccess/EORelationship.h | 231 + EOAccess/EORelationship.m | 2370 ++++++ EOAccess/EOSQLExpression.h | 229 + EOAccess/EOSQLExpression.m | 2878 +++++++ EOAccess/EOSQLExpressionPriv.h | 48 + EOAccess/EOSQLQualifier.h | 91 + EOAccess/EOSQLQualifier.m | 369 + EOAccess/EOStoredProcedure.h | 79 + EOAccess/EOStoredProcedure.m | 226 + EOAccess/EOUtilities.h | 105 + EOAccess/EOUtilities.m | 1039 +++ EOAccess/GNUmakefile | 123 + EOAccess/Makefile.postamble | 69 + EOAccess/Makefile.preamble | 72 + EOAccess/gdl2.gsdoc | 23 + EOAdaptors/GNUmakefile.in | 40 + EOAdaptors/Postgres95/GNUmakefile.in | 91 + EOAdaptors/Postgres95/Info.plist | 4 + EOAdaptors/Postgres95/Makefile.preamble | 61 + EOAdaptors/Postgres95/Makefile.preamble.in | 61 + EOAdaptors/Postgres95/Postgres95Adaptor.h | 104 + EOAdaptors/Postgres95/Postgres95Adaptor.m | 489 ++ EOAdaptors/Postgres95/Postgres95Channel.h | 89 + EOAdaptors/Postgres95/Postgres95Channel.m | 1451 ++++ EOAdaptors/Postgres95/Postgres95Context.h | 71 + EOAdaptors/Postgres95/Postgres95Context.m | 318 + .../Postgres95/Postgres95EOAdaptor.gsdoc | 23 + .../Postgres95/Postgres95SQLExpression.h | 57 + .../Postgres95/Postgres95SQLExpression.m | 299 + EOAdaptors/Postgres95/Postgres95Values.h | 79 + EOAdaptors/Postgres95/Postgres95Values.m | 330 + EOControl/EOAndQualifier.m | 194 + EOControl/EOCheapArray.h | 86 + EOControl/EOCheapArray.m | 446 ++ EOControl/EOClassDescription.h | 226 + EOControl/EOClassDescription.m | 1716 +++++ EOControl/EOControl.h | 52 + EOControl/EODataSource.h | 63 + EOControl/EODataSource.m | 119 + EOControl/EODebug.h | 266 + EOControl/EODebug.m | 402 + EOControl/EODetailDataSource.h | 62 + EOControl/EODetailDataSource.m | 271 + EOControl/EOEditingContext.h | 359 + EOControl/EOEditingContext.m | 3105 ++++++++ EOControl/EOFault.h | 182 + EOControl/EOFault.m | 590 ++ EOControl/EOFaultHandler.m | 374 + EOControl/EOFetchSpecification.h | 146 + EOControl/EOFetchSpecification.m | 497 ++ EOControl/EOGenericRecord.h | 61 + EOControl/EOGenericRecord.m | 1354 ++++ EOControl/EOGlobalID.h | 67 + EOControl/EOGlobalID.m | 176 + EOControl/EOKeyComparisonQualifier.m | 171 + EOControl/EOKeyGlobalID.h | 63 + EOControl/EOKeyGlobalID.m | 221 + EOControl/EOKeyValueArchiver.h | 142 + EOControl/EOKeyValueArchiver.m | 766 ++ EOControl/EOKeyValueCoding.h | 75 + EOControl/EOKeyValueCoding.m | 985 +++ EOControl/EOKeyValueCodingBase.h | 76 + EOControl/EOKeyValueCodingBase.m | 1989 +++++ EOControl/EOKeyValueQualifier.m | 258 + EOControl/EOMutableKnownKeyDictionary.h | 168 + EOControl/EOMutableKnownKeyDictionary.m | 947 +++ EOControl/EONSAddOns.h | 75 + EOControl/EONSAddOns.m | 434 ++ EOControl/EONotQualifier.m | 82 + EOControl/EONull.h | 45 + EOControl/EONull.m | 195 + EOControl/EOObjectStore.h | 90 + EOControl/EOObjectStore.m | 138 + EOControl/EOObjectStoreCoordinator.h | 108 + EOControl/EOObjectStoreCoordinator.m | 628 ++ EOControl/EOObserver.h | 138 + EOControl/EOObserver.m | 219 + EOControl/EOOrQualifier.m | 193 + EOControl/EOQualifier.h | 230 + EOControl/EOQualifier.m | 914 +++ EOControl/EOSortOrdering.h | 91 + EOControl/EOSortOrdering.m | 388 + EOControl/EOUndoManager.h | 38 + EOControl/EOUndoManager.m | 87 + EOControl/GNUmakefile | 129 + EOControl/Makefile.postamble | 74 + EOControl/Makefile.preamble | 73 + EOControl/gdl2control.gsdoc | 23 + EOModeler/EOModelExtensions.h | 77 + EOModeler/EOModelExtensions.m | 260 + EOModeler/GNUmakefile | 57 + EOModeler/Makefile.postamble | 69 + EOModeler/Makefile.preamble | 69 + GNUmakefile | 41 + Makefile.postamble | 83 + TODO | 20 + Tools/EOAttribute+GSDoc.h | 50 + Tools/EOAttribute+GSDoc.m | 133 + Tools/EOEntity+GSDoc.h | 48 + Tools/EOEntity+GSDoc.m | 133 + Tools/EOJoin+GSDoc.h | 48 + Tools/EOJoin+GSDoc.m | 79 + Tools/EOModel+GSDoc.h | 51 + Tools/EOModel+GSDoc.m | 149 + Tools/EORelationship+GSDoc.h | 50 + Tools/EORelationship+GSDoc.m | 139 + Tools/GNUmakefile | 96 + Tools/Makefile.postamble | 69 + Tools/Makefile.preamble | 77 + Tools/NSArray+GSDoc.h | 54 + Tools/NSArray+GSDoc.m | 117 + Tools/NSDictionary+GSDoc.h | 51 + Tools/NSDictionary+GSDoc.m | 97 + Tools/eomodeltemplate.gsdoc | 23 + Tools/gdl2gsdoc.gsdoc | 20 + Tools/gsdoc-model.m | 515 ++ Version | 17 + config.h.in | 35 + config/postgres.m4 | 56 + configure | 3636 +++++++++ configure.ac | 71 + gdl2.make.in | 49 + 165 files changed, 62782 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING.LIB create mode 100644 ChangeLog create mode 100644 EOAccess/EOAccess.h create mode 100644 EOAccess/EOAccessFault.h create mode 100644 EOAccess/EOAccessFault.m create mode 100644 EOAccess/EOAccessFaultPriv.h create mode 100644 EOAccess/EOAdaptor.h create mode 100644 EOAccess/EOAdaptor.m create mode 100644 EOAccess/EOAdaptorChannel.h create mode 100644 EOAccess/EOAdaptorChannel.m create mode 100644 EOAccess/EOAdaptorContext.h create mode 100644 EOAccess/EOAdaptorContext.m create mode 100644 EOAccess/EOAdaptorOperation.m create mode 100644 EOAccess/EOAdaptorPriv.h create mode 100644 EOAccess/EOAttribute.h create mode 100644 EOAccess/EOAttribute.m create mode 100644 EOAccess/EOAttributePriv.h create mode 100644 EOAccess/EODatabase.h create mode 100644 EOAccess/EODatabase.m create mode 100644 EOAccess/EODatabaseChannel.h create mode 100644 EOAccess/EODatabaseChannel.m create mode 100644 EOAccess/EODatabaseChannelPriv.h create mode 100644 EOAccess/EODatabaseContext.h create mode 100644 EOAccess/EODatabaseContext.m create mode 100644 EOAccess/EODatabaseContextPriv.h create mode 100644 EOAccess/EODatabaseDataSource.h create mode 100644 EOAccess/EODatabaseDataSource.m create mode 100644 EOAccess/EODatabaseOperation.h create mode 100644 EOAccess/EODatabaseOperation.m create mode 100644 EOAccess/EODatabaseOperationPriv.h create mode 100644 EOAccess/EOEntity.h create mode 100644 EOAccess/EOEntity.m create mode 100644 EOAccess/EOEntityPriv.h create mode 100644 EOAccess/EOExpressionArray.h create mode 100644 EOAccess/EOExpressionArray.m create mode 100644 EOAccess/EOJoin.h create mode 100644 EOAccess/EOJoin.m create mode 100644 EOAccess/EOModel.h create mode 100644 EOAccess/EOModel.m create mode 100644 EOAccess/EOModelGroup.h create mode 100644 EOAccess/EOModelGroup.m create mode 100644 EOAccess/EOPropertyListEncoding.h create mode 100644 EOAccess/EORelationship.h create mode 100644 EOAccess/EORelationship.m create mode 100644 EOAccess/EOSQLExpression.h create mode 100644 EOAccess/EOSQLExpression.m create mode 100644 EOAccess/EOSQLExpressionPriv.h create mode 100644 EOAccess/EOSQLQualifier.h create mode 100644 EOAccess/EOSQLQualifier.m create mode 100644 EOAccess/EOStoredProcedure.h create mode 100644 EOAccess/EOStoredProcedure.m create mode 100644 EOAccess/EOUtilities.h create mode 100644 EOAccess/EOUtilities.m create mode 100644 EOAccess/GNUmakefile create mode 100644 EOAccess/Makefile.postamble create mode 100644 EOAccess/Makefile.preamble create mode 100644 EOAccess/gdl2.gsdoc create mode 100644 EOAdaptors/GNUmakefile.in create mode 100644 EOAdaptors/Postgres95/GNUmakefile.in create mode 100644 EOAdaptors/Postgres95/Info.plist create mode 100644 EOAdaptors/Postgres95/Makefile.preamble create mode 100644 EOAdaptors/Postgres95/Makefile.preamble.in create mode 100644 EOAdaptors/Postgres95/Postgres95Adaptor.h create mode 100644 EOAdaptors/Postgres95/Postgres95Adaptor.m create mode 100644 EOAdaptors/Postgres95/Postgres95Channel.h create mode 100644 EOAdaptors/Postgres95/Postgres95Channel.m create mode 100644 EOAdaptors/Postgres95/Postgres95Context.h create mode 100644 EOAdaptors/Postgres95/Postgres95Context.m create mode 100644 EOAdaptors/Postgres95/Postgres95EOAdaptor.gsdoc create mode 100644 EOAdaptors/Postgres95/Postgres95SQLExpression.h create mode 100644 EOAdaptors/Postgres95/Postgres95SQLExpression.m create mode 100644 EOAdaptors/Postgres95/Postgres95Values.h create mode 100644 EOAdaptors/Postgres95/Postgres95Values.m create mode 100644 EOControl/EOAndQualifier.m create mode 100644 EOControl/EOCheapArray.h create mode 100644 EOControl/EOCheapArray.m create mode 100644 EOControl/EOClassDescription.h create mode 100644 EOControl/EOClassDescription.m create mode 100644 EOControl/EOControl.h create mode 100644 EOControl/EODataSource.h create mode 100644 EOControl/EODataSource.m create mode 100644 EOControl/EODebug.h create mode 100644 EOControl/EODebug.m create mode 100644 EOControl/EODetailDataSource.h create mode 100644 EOControl/EODetailDataSource.m create mode 100644 EOControl/EOEditingContext.h create mode 100644 EOControl/EOEditingContext.m create mode 100644 EOControl/EOFault.h create mode 100644 EOControl/EOFault.m create mode 100644 EOControl/EOFaultHandler.m create mode 100644 EOControl/EOFetchSpecification.h create mode 100644 EOControl/EOFetchSpecification.m create mode 100644 EOControl/EOGenericRecord.h create mode 100644 EOControl/EOGenericRecord.m create mode 100644 EOControl/EOGlobalID.h create mode 100644 EOControl/EOGlobalID.m create mode 100644 EOControl/EOKeyComparisonQualifier.m create mode 100644 EOControl/EOKeyGlobalID.h create mode 100644 EOControl/EOKeyGlobalID.m create mode 100644 EOControl/EOKeyValueArchiver.h create mode 100644 EOControl/EOKeyValueArchiver.m create mode 100644 EOControl/EOKeyValueCoding.h create mode 100644 EOControl/EOKeyValueCoding.m create mode 100644 EOControl/EOKeyValueCodingBase.h create mode 100644 EOControl/EOKeyValueCodingBase.m create mode 100644 EOControl/EOKeyValueQualifier.m create mode 100644 EOControl/EOMutableKnownKeyDictionary.h create mode 100644 EOControl/EOMutableKnownKeyDictionary.m create mode 100644 EOControl/EONSAddOns.h create mode 100644 EOControl/EONSAddOns.m create mode 100644 EOControl/EONotQualifier.m create mode 100644 EOControl/EONull.h create mode 100644 EOControl/EONull.m create mode 100644 EOControl/EOObjectStore.h create mode 100644 EOControl/EOObjectStore.m create mode 100644 EOControl/EOObjectStoreCoordinator.h create mode 100644 EOControl/EOObjectStoreCoordinator.m create mode 100644 EOControl/EOObserver.h create mode 100644 EOControl/EOObserver.m create mode 100644 EOControl/EOOrQualifier.m create mode 100644 EOControl/EOQualifier.h create mode 100644 EOControl/EOQualifier.m create mode 100644 EOControl/EOSortOrdering.h create mode 100644 EOControl/EOSortOrdering.m create mode 100644 EOControl/EOUndoManager.h create mode 100644 EOControl/EOUndoManager.m create mode 100644 EOControl/GNUmakefile create mode 100644 EOControl/Makefile.postamble create mode 100644 EOControl/Makefile.preamble create mode 100644 EOControl/gdl2control.gsdoc create mode 100644 EOModeler/EOModelExtensions.h create mode 100644 EOModeler/EOModelExtensions.m create mode 100644 EOModeler/GNUmakefile create mode 100644 EOModeler/Makefile.postamble create mode 100644 EOModeler/Makefile.preamble create mode 100644 GNUmakefile create mode 100644 Makefile.postamble create mode 100644 TODO create mode 100644 Tools/EOAttribute+GSDoc.h create mode 100644 Tools/EOAttribute+GSDoc.m create mode 100644 Tools/EOEntity+GSDoc.h create mode 100644 Tools/EOEntity+GSDoc.m create mode 100644 Tools/EOJoin+GSDoc.h create mode 100644 Tools/EOJoin+GSDoc.m create mode 100644 Tools/EOModel+GSDoc.h create mode 100644 Tools/EOModel+GSDoc.m create mode 100644 Tools/EORelationship+GSDoc.h create mode 100644 Tools/EORelationship+GSDoc.m create mode 100644 Tools/GNUmakefile create mode 100644 Tools/Makefile.postamble create mode 100644 Tools/Makefile.preamble create mode 100644 Tools/NSArray+GSDoc.h create mode 100644 Tools/NSArray+GSDoc.m create mode 100644 Tools/NSDictionary+GSDoc.h create mode 100644 Tools/NSDictionary+GSDoc.m create mode 100644 Tools/eomodeltemplate.gsdoc create mode 100644 Tools/gdl2gsdoc.gsdoc create mode 100644 Tools/gsdoc-model.m create mode 100644 Version create mode 100644 config.h.in create mode 100644 config/postgres.m4 create mode 100755 configure create mode 100644 configure.ac create mode 100644 gdl2.make.in diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..523c9c2 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,4 @@ +Mirko Viviani +Gerald Siebke +Manuel Guesdon +David Ayers diff --git a/COPYING.LIB b/COPYING.LIB new file mode 100644 index 0000000..eb685a5 --- /dev/null +++ b/COPYING.LIB @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..467de3e --- /dev/null +++ b/ChangeLog @@ -0,0 +1,751 @@ +2002-11-14 Manuel Guesdon + + * EOAcces/EODatabaseDataSource.m: + o corrected bug in -description + * EOAdaptors/Postgres95/Postgres95SQLExpression.m + o change in +formatValue:forAttribute: to handle string value for dates + +2002-11-14 Mirko Viviani + + * EOAdaptors/*, EOAccess/*, EOControl/*: removed some warnings. + +2002-11-13 Manuel Guesdon + * EOAcces/EODatabaseContext.m: + o corrected bug + o logs + * EOAccess/EODatabaseOperation.m: + o -setDatabaseOperator: change to not update deleted objetcs + * EOAccess/EOEntity.m: + o -_attributesToFetch added exception handling + * EOAccess/EOSQLExpression: + o use sqlExpressionWithEntity instead of alloc/init + * EOControl/EOEditingContext.m: + o _processOwnedObjectsUsingChangeTable:deleteTable: + bug correction in new/existing value handling + o doc + * EOControl/EOGenericRecord.m: + o log changes + * EOControl/EOKeyValueCoding.m: + o added -takeStoredValue:forKeyPath: + o added -storedValuesForKeyPaths: + o corrected bug in NSArray -valueForKey: + o corrected bugs in NSArray -valueForKeyPath: + * EOAccess/EOUtilities.m + o handle nil value in rawRowsMatchingValue:forKey:entityNamed: + o handle nil value in objectsMatchingValue:forKey:entityNamed: + o handle nil value in objectWithPrimaryKeyValue:entityNamed: + * EOAccess/EOAttribute.m + o destroy docComment in -dealloc + * EOAdaptors/Postgres98/Postgres95Values.m: + o comment + o use stringWithCString.. instead of alloc/init/release + * EOControl/EOMultipleKnownKeyDictionary.h + o added -debugDescription + * EOControl/EONull.m: + o added -NSNull -valueForKey: + * EOAccess/EOQualifier.m: + o in getKey: autorelease key + o in -qualifierWithQualifierFormat:varargList: + user [NSMutableArray array] instead [NSMutableArray new]/DESTROY + to avoid memory leak if an exception is raised + +2002-11-04 David Ayers + + * EOControl/EOSortOrdering.m: + o changed -sortedArrayUsingKeyOrderArray: + * EOControl/EOQualifier.m: + o improved -qualifierWithQualifierFormat: parsing + +2002-10-31 David Ayers + + * EOControl/EOQualifier.m: + o improved -qualifierWithQualifierFormat: parsing + o added NSNumber -initWithString as EOQualiferExtra + * EOControl/EOKeyValueQualifier.m: + o changed -description + * EOControl/EOKeyComparisonQualifier.m: + o changed -description + +2002-09-22 Mirko Viviani + + * Makefile.postamble: install gdl2.make. + +2002-09-22 Mirko Viviani + + * configure.ac: added adaptors configuration. + * config/postgres.m4: check for postgres db. + * EOAdaptors/Postgres95/GNUmakefile.in: new file. + * EOAdaptors/Postgres95/Makefile.preamble.in: new file. + +2002-09-20 Mirko Viviani + + * configure.ac: new file. + * gdl2.make.in: new file. + * config.h.in: new file. + +2002-09-20 Mirko Viviani + + * Indented all the sources and removed many warnings. + * Moved EOCheapArray.m|h, EONSAddOns.m|h and EODebug.m|h to EOControl. + * Moved EOUtilities.m|h to EOAccess. + * Moved EOQualifierSQLGeneration in EOAccess/EOSQLQualifier + +2002-06-03 Manuel Guesdon + * EOAdaptors/Postgres95/Postgres95SQLExpression.m: + o NSWarn -> NSWarnLog + * EOControl/EOKeyValueArchiver.m: + o added -isThereValueForKey: in EOKeyValueUnarchiver + * EOControl/EOKeyValueArchiver.h: + o added -isThereValueForKey: in EOKeyValueUnarchiver + * EOControl/EOSQLExpression.m: + o changes for usesDistincts + o logs + * EOAccess/EODatabaseChannel.m: + o fix for refetched objects + * EOAccess/EODatabaseContext.m: + o fixes in recordChangesInEditingContext + * EOAccess/EODatabaseDataSource.m: + o logs + * EOAccess/EONSAddOns.h/.m + o added NSArray -arrayExcludingObject: + o added NSArray -containsIdenticalObjectsWithArray: + * EOAccess/EORelationship.h/.m: + o added isBidirectional: and associated methods (for use with smartTakeValue:forKey:) + * EOControl/EOClassDescription.h/.m: + o added -relationshipNamed: + o added -anyRelationshipNamed: + * EOControl/EOGenericRecord.m: + o added -smartTakeValue:forKey: + * EOControl/EOObjectStoreCoordinator.m: + o logs + +2002-05-14 Manuel Guesdon + * EOControl/EOEditingContext.m: + o changes in -saveChangesInEditingContext: to avoid return in the middle of the method + o logs + * EOAccess/EODatabaseContext.m: + o add rollbackChanges on exception in -saveChangesInEditingContext: + o corrected bug in initializeObject:row:entity:editingContext: + o logs + * EOControl/EOKeyValueQualifier.m: + o implementation of flatten case in -schemaBasedQualifierWithRootEntity: + o logs + * EOControl/EODetailDataSource.m + o correct bugs by using -decodeObjectForKey: in -initWithKeyValueUnarchiver: + o changed _masterEntityName to _masterClassDescriptionName + o added -classDescriptionForObjects + o logs + * EOControl/EODetailDataSource.h: + o changed _masterEntityName to _masterClassDescriptionName + o added -classDescriptionForObjects + * EOControl/EODataSource.m: + o logs + * EOControl/EOGenericRecord.m: + o added -willChange call in _setValueForKey:object:selector:type:size:offset: + * EOControl/EOMutableKnownKeyDictionary.m: + o corrected bug in -containsObjectsNotIdenticalTo: + o logs + * EOAccess/EOSQLExpression.m: + o logs + * EOAdaptors/Postgres95/Postgres95SQLExpression.m: + o logs + o corrected bugs for empty strings in +formatValue:forAttribute: + * EOAccess/EODatabaseDataSource.m + o logs + * EOAccess/EOEntity.m + o logs + * EOControl/EOQualifier.m: + o logs + * EOControl/EOOrQualifier.m: + o logs + * EOControl/EOAndQualifier.m: + o logs + * EOControl/EOObserver.m: + o logs + * EOAccess/EODatabase.m: + o logs + o avoid fault access in -entityForObject: + +2002-04-15 Manuel Guesdon + * EOAccess/EOFetchSpecification.m: + o changed -fetchSpecification into +fetchSpecification + * EOAccess/EOKeyValueCoding.m: + o logs + o corrected bug: added special case "count" in NSArray -valueForKeyPath: + * EOAccess/EOGenericRecord.m: + o logs + * EOControl/EODetailDataSource.h: + o added -initWithKeyValueUnarchiver: + * EOControl/EODetailDataSource.m: + o added -initWithKeyValueUnarchiver: + * EOControl/EOKeyValueArcher.m: + o added EOKeyValueArchivingContainer +keyValueArchivingContainer + o corrected not autorelease bug in -_objectForPropertyList: + o logs + * EOControl/EODatabaseDataSource.m: + o logs + +2002-04-01 Manuel Guesdon + * EOAccess/EOModel.h: + o added +version + * EOAccess/EOStoredProcedure.h: + o added +storedProcedureWithPropertyList:owner: + * EOAccess/EOEntity.h: + o added +entityWithPropertyList:owner: + o added -setDocComment: + o added +entityClassDescriptionWithEntity: + * EOAccess/EOEntity.m: + o corrected bug in _keyMapForIdenticalKeyRelationshipPath: (dictionary construction) + * EOAccess/EOEntityPriv.h: + o retyped -_parseDescription:isFormat:arguments:; + * EOAccess/EORelationship.h: + o added +relationshipWithPropertyList:owner: + * EOAccess/EOAttribute.h: + o added +attributeWithPropertyList:owner: + o added -setInternalInfo: + o added -_normalizeDefinition:path: + + * EOAccess/EOAttribute.m: + o use an id instead of a string for userInfo,... + o added -setInternalInfo: + * EOAccess/EOExpressionArray.h: + o added -valueForSQLExpression: + +2002-04-01 Manuel Guesdon + * EOControl/EODetailDataSource.h/.m: + o added +detailDataSourceWithMasterDataSource:detailKey: + * EOAccess/EODatbaseDataSource.m: + o changed allocations + * EOAccess/EODatabase.m: + o changed allocations + * EOAccess/EOEntity.m: + o changed allocations + o corrected not autorelease bug in EOEntity -classDescriptionForInstances + * EOControl/EOGlobalID.h/.m: + o added EOTemporaryGlobalID +temporaryGlobalID + * EOControl/EIEditingContext.m: + o changed allocations + * EOControl/EOKeyValueQualifier.m: + o changed allocations + * EOControl/EOObjectStoreCoordinator.m: + o changed allocations + * EOKeyComparisonQualifier.m: + o added +qualifierWithLeftKey:operatorSelector:rightKey: + * EONotQualifier.m: + o added +qualifierWithQualifier: + * EOQualifier.m: + o changed allocations + * EOAccess/EOAdaptorContext.h/.m: + o added +adaptorContextWithAdaptor: + * EOAdaptors/Postgres95/Postgres9Adaptor.m: + o changed allocations + * EOAdaptors/Postgres95/Postgres9Channel.m: + o changed allocations + * EOAdaptors/Postgres95/Postgres9Context.m: + o changed allocations + * EOAccess/EOModel.h/.m: + o added +model + * EOAccess/EOAdaptorChannel.h/.m + o added +adaptorChannelWithAdaptorContext: + * EOAdaptors/Postgres95/Postgres9Values.m: + o changed allocations + +2002-03-29 Manuel Guesdon + * EOAccess/EODatabaseOperation.m + o logs + * EOAccess/EODatabaseContext.h/.m + o logs + o added +databaseContextWithDatabase: + o change allocations + * EOAccess/EORelationship.m + o logs + o corrected not autorelease bug in _foreignKeyForSourceRow: + o added +relationshipWithPropertyList:owner: + * EOAccess/EOJoin.h/.m: + o added +joinWithSourceAttribute:destinationAttribute: + + * EOAccess/EOSQLExpression.m: + o added +sqlExpressionWithEntity: + * EOAccess/EOAttribute.m: + o added +attributeWithPropertyList:owner: + + * EOAdaptors/Postgres95/Postgres95Channel.m + o logs + * EOAccess/EODatabaseChannel.m + o logs + o added +databaseChannelWithDatabaseContext: + * EOAccess/EOFault.m: + o logs + * EOAccess/EOFetchSpecification.m/.h + o added +fetchSpecification + * EOControl/EOUtilities.m: + o corrected not autorelease bug in -objectsMatchingValues:entityNamed: + o change qualifiers allocations + * EOAccess/EOAndQualifier.m: + o added EOAndQualifier +qualifierWithQualifierArray: + o added EOAndQualifier +qualifierWithQualifiers: + * EOAccess/EOOrQualifier.m: + o added EOOrQualifier +qualifierWithQualifierArray: + * EOAccess/EOQualifier.h + o added EOAndQualifier +qualifierWithQualifierArray: + o added EOOrQualifier +qualifierWithQualifierArray: + * EOAccess/EOEntity.m: + o changed EOMutableKnownKeyDictionary allocation in -_dictionaryForProperties + * EOAccess/EOMutableKnownKeyDictionary.h/.m: + o added +dictionaryFromDictionary:subsetMapping: + * EOAccess/EOModel.h/.m + o added +modelWithContentsOfFile: + o corrected not autorelease bug + o allocation changes + * EOAccess/EOModelGroup.m: + o Changed EOModel allocation + * EOAccess/EODatabase.h/.m: + o added +databaseWithModel: + * EOAccess/EOAccessFault.h/.m + o added EOAccessFaultHandler +accessFaultHandlerWithGlobalID:databaseContext:editingContext: + o added EOAccessArrayFaultHandler + +accessArrayFaultHandlerWithSourceGlobalID:relationshipName:databaseContext:editingContext: + * EOAccess/EODatabaseOperation.h/.m: + o added EODatabaseOperation +databaseOperationWithGlobalID:object:entity: + * EOAccess/EOAdaptorOperation.h/.m: + o added EOAdaptorOperation +adaptorOperationWithEntity: + * EOAccess/EODatabaseDataSource.m: + o allocation changes + * EOAccess/EOStoredProcedure.m: + o corrected not autorelease bug in -initWithPropertyList:owner: + + +2002-03-28 Manuel Guesdon + * EOAccess/EODatabaseChannel.m + o removed logs + o changed logs + * EOAdaptors/Postgres95/Postgres95Channel.m + o removed logs + * EOAccess/EORelationship.m: + o NSAssert + o added _docComment and associated methods + * EOAccess/EORelationship.h: + o added _docComment and associated methods + * EOAccess/EOSQLExpression.m: + o NSAssert + o logs + * EOAccess/EOEntity.m: + o doc + o logs + o added _docComment and associated methods + * EOAccess/EOEntity.h: + o added _docComment and associated methods + + * EOAccess/EOModel.h/.m: + o added -adaptorClassname + o added _version and -version + o added _docComment and associated methods + * EOAccess/EOAttribute.h/.m: + o added _docComment and associated methods + + * EOAccess/EOAdaptorChannel.m + o logs + * EOAdaptors/Postgres95/Postgres95SQLExpression.m: + o corrected bug in formatValue:forAttribute: + * added Tools/ + +2002-03-25 Manuel Guesdon + * EOAccess/GNUmakefile: + o removed -SystemProjects System + o added -Declared EOAccess + * EOControl/GNUmakefile: + o removed -SystemProjects System + o added -Declared EOControl + * EOAdaptors/Postgres95/GNUmakefile: + o removed -SystemProjects System + o added -Declared EOAdaptors/PostgreSQL + * EOControl/EOGenericRecord.m: logs + * EOAccess/EODebug.h: added EOFLOGClassFnStartCond EOFLOGClassFnStopCond + * EOAccess/EODatabaseChannel.m: logs + * EOAccess/EORelationship.m: + o setDefinition + o corrected bug in _makeFlattenedInverseRelationship + * EOAccess/EOEntity.m + o logs + * EOControl/EOQualifier.h + o added qualifierWithKey:operatorSelector:value: + * EOControl/EOKeyValueQualifier.m: + o added qualifierWithKey:operatorSelector:value: + * EOAccess/EOModel.m: + o removed assert for non EOGenericRecord class in -_classDescriptionNeeded: + +2002-03-07 Manuel Guesdon + Too much changes + +2001-04-10 Mirko Viviani + + * EOAccess/EOSQLExpression.m ([EOSQLExpression + +foreignKeyConstraintStatementsForRelationship:]): implemented. + +2001-04-07 Mirko Viviani + + * EOControl/EOKeyValueCoding.m: import EOControl.h + * EOControl/EONull.m: likewise. + * EOAccess/EOModel.m ([EOModel -writeToFile:]): implemented. + ([EOModel -encodeTableOfContentsInfoPropertyList:]): implemented. + * EOAccess/EORelationship.m ([EORelationship -setEntity:]): remove self + from previous entity. + ([EORelationship -setDefinition:]): remove joins. + +2001-01-12 Mirko Viviani + + * EOModeler: new library. + * EOModeler/EOModelExtensions.m/.h: EOModeler categories needed by + eogenerator. + * EOControl/EOKeyValueCoding.m ([NSArray -valueForKey:]): fixed @x key. + +2001-01-06 Mirko Viviani + + * EOControl/EOControl.h: defined FOUNDATION_HAS_KVC to use Foundation + key value coding. + * EOAccess/EOAttribute.m ([EOAttribute + -adaptorValueByConvertingAttributeValue:]): use EONull null object. + * EOAccess/EOSQLExpression.m ([EOSQLExpression -sqlStringForSelector: + value:]): likewise. + * EOControl/EOKeyValueCoding.m ([NSObject -takeValuesFromDictionary:]): + ([NSObject -takeStoredValuesFromDictionary:]): likewise. + defined FOUNDATION_HAS_KVC to use Foundation key value coding. + +2001-01-03 Mirko Viviani + + * EOAccess/EODatabaseContext.m ([EODatabaseContext + -faultForGlobalID:editingContext:]): use the correct class property + array. + +2000-12-23 Mirko Viviani + + * EOAccess/EOEntity.m ([EOEntity -isPrimaryKeyValidInObject:]): fixed. + Do not returns from inside an exception handler. + * EOAccess/EODatabaseContext.m ([EODatabaseContext + -prepareForSaveWithCoordinator:editingContext:]): bug fix. Do not + release an autoreleased object. + * EOAccess/EODatabaseDataSource.m ([EODatabaseDataSource + -fetchSpecificationForFetch]): fixed fetch qualifier. + * EOControl/EOKeyValueQualifier.m ([EOKeyValueQualifier + -copyWithZone:]): do not copy _value. + * EOControl/EOAndQualifier.m ([EOAndQualifier -copyWithZone:]): use + correct zone. + * EOControl/EOOrQualifier.m ([EOOrQualifier -copyWithZone:]): likewise. + * EOControl/EOKeyComparisonQualifier.m ([EOKeyComparisonQualifier + -copyWithZone:]): likewise. + +2000-12-20 Mirko Viviani + + * EOAccess/EODatabaseContext.m ([EODatabaseContext + -_recordChangesForObjects:operator:]): create dbOperation with the + correct entity for to-many relationship objects. + +2000-12-11 Mirko Viviani + + * EOAccess/EOModel.m ([EOModel -_registerClassDescForClass:]): + check for NULL _entitiesByClass + ([EOModel -dealloc]): release _entitiesByClass + ([EOModel -removeEntity:]): bug fix. + + * EOAdaptors/Postgres95/Postgres95Channel.m ([Postgres + -_evaluateCommandsUntilAFetch]): raise an exception on error. + +2000-12-10 Mirko Viviani + + * EOControl/EOKeyValueCoding.m (newGetStoredBinding): fixed value of + class variable. + +2000-12-09 Mirko Viviani + + * EOAccess/EOModel.m ([EOModel -_registerClassDescForClass:]): fixed + class description registration. + ([EOModel -_registerClassDescForEntityName:]): likewise. + ([EOModel -addEntity:]), ([EOModel -removeEntity:]): save EOEntity in + _entitiesByClass. + +2000-12-08 Mirko Viviani + + * EOAccess/EODatabaseContext.m ([EODatabaseContext + -prepareForSaveWithCoordinator:editingContext:]): get the object value + if the key is a class property. + Added code to handle propagatesPrimaryKey for to many relationships. + Fixed code that merges pk values. + * EOControl/EOClassDescription.m ([EOClassDescription -awakeObject: + fromInsertionInEditingContext:]): use NSMutableArray for to many + relationships. + +2000-12-08 Mirko Viviani + + * EOAccess/EODatabaseContext.m ([EODatabaseContext -faultForGlobalID: + editingContext:]): set only class property's object values. + ([EODatabaseContext -faultForRawRow:entityNamed:editingContext:]): + likewise. + ([EODatabaseContext -_recordChangesForObjects:operator:]): likewise. + ([EODatabaseContext -batchFetchRelationship:forSourceObjects: + editingContext:]): get key value from snapshot rather than in the + object. + +2000-12-06 Mirko Viviani + + * EOControl/EOKeyValueCoding.m ([NSObject + -handleQueryWithUnboundKey:]): raise an EOUnknownKeyException with + the correct userInfo. + ([NSObject -handleTakeValue:forUnboundKey:]): likewise. + * EOAccess/EOEntity.m ([EOEntity -isPrimaryKeyValidInObject:]): + check valueForKey: exception. + * EOControl/EOClassDescription.m ([NSObject -changesFromSnapshot:]): + check for EONull values as toMany relationship array. + * EOControl/EOEditingContext.m ([EOEditingContext + -processRecentChanges]): check for EONull values in dictionary. + * EOAccess/EOModel.m ([EOModel -initWithPropertyList:owner:]): check + for an exception in the entity awakeWithPropertyList method. + * EOAccess/EOJoin.m ([EOJoin -initWithSourceAttribute: + destinationAttribute:]): raise exception if source or destination is + nil. + +2000-12-05 Mirko Viviani + + * EOAccess/EODatabaseChannel.m ([EODatabaseChannel -fetchObject]): + fixed refreshing objects. + * EOControl/EOKeyValueCoding.m ([NSArray -valueForKey:]): fixed array + and string selector. + * EOAccess/EOUtilities.m ([EOEditingContext -objectsForEntityNamed:]): + ([EOEditingContext -primaryKeyForObject:]), ([EOEditingContext + -entityForObject:]): implemented. + * EOAccess/EODatabaseContext.m ([EODatabaseContext + -prepareForSaveWithCoordinator:editingContext:]): lock the database + context. + ([EODatabaseContext -commitChanges]), ([EODatabaseContext + -rollbackChanges]): unlock the database context + ([EODatabaseContext -registerLockedObjectWithGlobalID:]): fixed zone + size. + +2000-12-04 Mirko Viviani + + * EOAccess/EODatabaseContext.m ([EODatabaseContext + -_recordChangesForObjects:operator:]): when updating relationship keys + look also in the object snapshot. + +2000-12-03 Mirko Viviani + + * EOAccess/EOSQLExpression.m ([EOSQLExpression + -sqlStringForKeyValueQualifier:]): bug fix. + * EOAccess/EOUtilities.m ([EOEditingContext -objectsMatchingValue: + forKey:entityNamed:]): implemented. + +2000-12-01 Mirko Viviani + + * EOAccess/EOUtilities.m/.h: new files. + * EOAccess/EOAccess.h: addes EOUtilities.h + +2000-11-23 Mirko Viviani + + * EOControl/EOEditingContext.m ([EOEditingContext + -initializeObject:withGlobalID:editingContext:]): ensure that the next + 'willChange' notification will be processed for the initialized object. + * EOAccess/EOEntity.m ([EOEntity -globalIDForRow:]): fixed globalID + values order for compound PKs. + +2000-11-22 Mirko Viviani + + * EOAccess/EODatabaseOperationPriv.h: new file. + * EOAccess/EODatabaseOperation.m ([EODatabaseOperation + -_setGlobalID:]): new method. + * EOAccess/EODatabaseContext.m ([EODatabaseContext + -prepareForSaveWithCoordinator:editingContext:]): fixed propagates + primary key code. + ([EODatabaseContext -_recordChangesForObjects:operator:]): in toOne rel + discard PK to PK joins. Discard 'empty' toOne rels. + ([EODatabaseContext -_setGlobalID:forDatabaseOperation:): new method. + It replaces the globalID for the gived operation. + * EOAccess/EORelationship.m ([EORelationship + -initWithPropertyList:owner:]): check for 'propagatesPrimaryKey'. + * EOAccess/EOSQLExpression.m ([EOSQLExpression + -addOrderByAttributeOrdering:]): use compare selector defines. Call + -sqlStringForAttributeNamed: for the sortOrdering key. + +2000-11-19 Mirko Viviani + + * EOControl/EOFault.m ([EOFault +makeObjectIntoFault:withHandler:]): + do not turn into fault the nil object. + * EOControl/EOEditingContext.m ([EOEditingContext + -refaultObject:withGlobalID:editingContext:]): does nothing if objects + is nil. + * EOAccess/EODatabaseContext.m ([EODatabaseContext + -refaultObject:withGlobalID:editingContext:]): likewise. + ([EODatabaseContext -refaultObject:withGlobalID:editingContext:]): does + not remove the snapshot. + ([EODatabaseChannel -fetchObject]): fix for refreshing object. + * EOControl/EOSortOrdering.m ([NSMutableArray + -_sortUsingKeyOrder:fromIndex:count:]): use defined value for compare + selectors. Fix when aValue or bValue are nil. + ([EONull -compareAscending:]), ([EONull -compareDescending:]), + ([EONull -compareCaseInsensitiveAscending:]): ([EONull + -compareCaseInsensitiveDescending:]): if value to be compared is be + treat it as EONull. + +2000-11-18 Mirko Viviani + + * EOControl/EOEditingContext.m ([EOEditingContext + -processRecentChanges]): get toOne and toMany keys from object instead + of the editingContext. + + * EOAccess/EODatabaseContext.m ([EODatabaseContext + -_recordChangesForObjects:operator:]): new method. Fixed foreign key + update for inserted objects of toOne relationships. Fixed dictionary + and foreign key update for toMany relationships. + ([EODatabaseContext -recordChangesInEditingContext]): moved code into + -_recordChangesForObjects:operator: and check changes also in inserted + objects. + ([EODatabaseContext -_dbOperationWithObject:operator:]): new method. + Find db operation for the given object and operator. + ([EODatabaseContext -commitChanges]), ([EODatabaseContext + -rollbackChanges]): reset ivars if no transaction in progress. + +2000-11-16 Mirko Viviani + + * EOControl/EOEditingContext.m ([EOEditingContext + -_handleObjectsChangedInStoreNotification:]): refault updated objects. + + * EOAccess/EODatabaseChannel.m ([EODatabaseChannel -fetchObject]): + fixed notification for refreshed objects. + * EOAccess/EOSQLExpression.m ([EOSQLExpression + -sqlStringForAttribute:]): fix id attribute is derived. + * EOAccess/EOEntity.m ([EOEntity -setAttributesUsedForLocking:]): fix + release of the array when no valid attributes are found. + ([EOEntity -setPrimaryKeyAttributes:]): likewise. + * EOAccess/EODatabase.m ([EODatabase -forgetSnapshotsForGlobalIDs:]): + ([EODatabase -forgetSnapshotForGlobalID:]): use defined userInfo string + instead of an hardcoded one. + +2000-11-05 Mirko Viviani + + * EOControl/EOSortOrdering.m ([NSArray + -sortedArrayUsingKeyOrderArray:]): implemented. + ([NSMutableArray -sortUsingKeyOrderArray:]): not fully implemented. + ([NSMutableArray -_sortUsingKeyOrder:fromIndex:count:]): modified + gnustep-base shell sort. + ([EOSortOrdering -initWithCoder:]): fixed. + ([EONull -compareAscending:]): implemented. + ([EONull -compareDescending:]): implemented. + ([EONull -compareCaseInsensitiveAscending:]): implemented. + ([EONull -compareCaseInsensitiveDescending:]): implemented. + + * EOAdaptors/Postgres95/Postgres95Channel.m ([Postgres + -_describeResults]): does not coerce attribute className. + * EOAdaptors/Postgres95/Postgres95Values.m: fixed pg calendar format. + * EOAdaptors/Postgres95/Postgres95SQLExpression.m ([Postgres -assembleSelectStatementWithAttributes:lock:qualifier:fetchOrder:selectString:columnList:tableList:whereClause:joinClause:orderByClause:lockClause:]): does not return + mutableCopy of the string. + ([Postgres +formatValue:forAttribute:]): implemented. Added code from + Turbocat's development. + + * EOAccess/EOSQLExpression.m: does not return mutableCopy of a string. + ([EOSQLExpression +formatValue:forAttribute:]): return value unchanged. + ([EOSQLExpression -sqlStringForValue:attributeNamed:]): bug fix ? + moved code from +[formatValue:forAttribute:] + + * EOControl/EOAndQualifier.m ([EOAndQualifier + -sqlStringForSQLExpression:]): doesn't return mutableCopy of a string. + * EOControl/EOOrQualifier.m ([EOOrQualifier + -sqlStringForSQLExpression:]): likewise. + + * EOControl/EODetailDataSource.m ([EODetailDataSource + -initWithMasterClassDescription:detailKey:]): set + masterClassDescription. + + * EOAccess/EOSQLExpression.m + ([EOSQLExpression -addCreateClauseForAttribute:]): + ([EOSQLExpression -allowsNullClauseForConstraint:]): + ([EOSQLExpression -columnTypeStringForAttribute:]): + ([EOSQLExpression +dropTableStatementsForEntityGroup:]): + ([EOSQLExpression +createTableStatementsForEntityGroup:]): + ([EOSQLExpression +primaryKeyConstraintStatementsForEntityGroup:]): + ([EOSQLExpression +primaryKeySupportStatementsForEntityGroup:]): + ([EOSQLExpression +dropPrimaryKeySupportStatementsForEntityGroup:]): + ([EOSQLExpression +createTableStatementsForEntityGroups:]): + ([EOSQLExpression +dropTableStatementsForEntityGroups:]): + ([EOSQLExpression +primaryKeyConstraintStatementsForEntityGroups:]): + ([EOSQLExpression +primaryKeySupportStatementsForEntityGroups:]): + ([EOSQLExpression +dropPrimaryKeySupportStatementsForEntityGroups:]): + ([EOSQLExpression +appendExpression:toScript:]): + ([EOSQLExpression +schemaCreationScriptForEntities:options:]): + ([EOSQLExpression +schemaCreationStatementsForEntities:options:]): + ([EOSQLExpression -prepareConstraintStatementForRelationship: + sourceColumns:destinationColumns:]): + ([EOSQLExpression +createDatabaseStatementsForConnectionDictionary: + administrativeConnectionDictionary:]): + ([EOSQLExpression +dropDatabaseStatementsForConnectionDictionary: + administrativeConnectionDictionary:]): + ([EOSQLExpression +selectStatementForContainerOptions]): implemented. + + * EOAccess/EOEntity.m ([EOEntity -primaryKeyRootName]): bug fix: calls + -primaryKeyRootName on the _parent entity instead of -externalName. + + * EOAccess/EOSchemaGeneration.h: new file. + + * EOAccess/EOAccess.h: added EOSchemaGeneration.h + + * EOAccess/EOModel.m ([EOModel -initWithContentsOfFile:]):, + ([EOModel -initWithTableOfContentsPropertyList:path:]): fixed _name and + _path. + ([EOModel -initWithPropertyList:owner:]): use _path instead of _name. + + * EOAccess/EOModelGroup.m ([EOModelGroup +globalModelGroup]): search + models in bundles and frameworks. + + * EOAccess/EOAdaptor.m ([EOAdaptor +adaptorWithName:]): changed adaptor + from bundle to framework. Looks for EOAdaptor.framework + ([EOAdaptor -createDatabaseWithAdministrativeConnectionDictionary:]): + ([EOAdaptor -dropDatabaseWithAdministrativeConnectionDictionary:]): + new methods. + * EOAccess/EOAdaptor.h: added include file + + * EOAccess/GNUmakefile: added LIBRARIES_DEPEND_UPON + * EOControl/GNUmakefile: Likewise. + +2000-10-05 Manuel Guesdon + + * EOAccess/EODatabaseChannel.m: added NSDebugMLog and NSAssert + * EOAccess/EODatabaseDataSource.m: added NSDebugMLog and NSAssert + * EOAccess/EOEntity.m: added NSDebugMLog and NSAssert + * EOAccess/EOModel.m: modified -init + * EOControl/EOFetchSpecification.h/.m: added EOKeyValueUnarchiver support + * EOControl/EOKeyValueArchiver.h/.m: implemented EOKeyValueUnarchiver + * EOControl/GNUmakefile: added EOKeyValueArchiver + +2000-09-28 Manuel Guesdon + + * EOAccess/EODatabaseContext.m: added NSDebugMLog and NSAssert + * EOAccess/EODatabaseChannel.m: added NSDebugMLog and NSAssert + * EOAdaptors/Postgres95/Postgres95Channel.m : added NSDebugMLog + and NSAssert + * EOAccess/EODatabase.m: added NSDebugMLog and NSAssert + +2000-09-24 Manuel Guesdon + + * config.mak: added include directories in POSTGRES95_CFLAGS + +2000-09-23 Mirko Viviani + + * EOControl/EOQualifier.m (getKey): fixed pointer in key-value parsing. + +2000-09-17 Mirko Viviani + + * EOAdaptors/Postgres95/GNUmakefile: remove Postgres95Exceptions.h + +2000-09-17 Mirko Viviani + + Patches by David Wetzel + * EOAccess/EOAdaptorContext.m ([EOAdaptorContext -initWithAdaptor:]): + set default debug. + + * EOAccess/EOModel.m ([EOModel +findPathForModelNamed:]): look also + in the current dir. + + * EOControl/EOObjectStoreCoordinator.m ([EOObjectStoreCoordinator + -objectStoreForGlobalID:]), ([EOObjectStoreCoordinator + -objectStoreForObject:]), ([EOObjectStoreCoordinator + -objectStoreForFetchSpecification:]): bug fix: changed notification + object. + + diff --git a/EOAccess/EOAccess.h b/EOAccess/EOAccess.h new file mode 100644 index 0000000..4f5dbc0 --- /dev/null +++ b/EOAccess/EOAccess.h @@ -0,0 +1,73 @@ +/* + EOAccess.h + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOAccess_h__ +#define __EOAccess_h__ + +#import + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + + +#endif /* __EOAccess_h__ */ diff --git a/EOAccess/EOAccessFault.h b/EOAccess/EOAccessFault.h new file mode 100644 index 0000000..ebe2be0 --- /dev/null +++ b/EOAccess/EOAccessFault.h @@ -0,0 +1,114 @@ +/* + EOAccessFault.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: June 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOAccessFault_h__ +#define __EOAccessFault_h__ + + +#import + + +@class EODatabaseContext; +@class EOKeyGlobalID; + + +@interface EOAccessGenericFaultHandler:EOFaultHandler +{ + unsigned int _generation; + EOAccessGenericFaultHandler *_next; + EOAccessGenericFaultHandler *_prev; +} + +- (void)linkAfter: (EOAccessGenericFaultHandler *)faultHandler + usingGeneration: (unsigned int)gen; +- (EOAccessGenericFaultHandler *)next; +- (EOAccessGenericFaultHandler *)previous; +- (unsigned int)generation; + +@end + + +@interface EOAccessFaultHandler:EOAccessGenericFaultHandler +{ + EOKeyGlobalID *gid; + EODatabaseContext *databaseContext; + EOEditingContext *editingContext; +} + ++ (EOAccessFaultHandler *)accessFaultHandlerWithGlobalID: (EOKeyGlobalID *)globalID + databaseContext: (EODatabaseContext *)dbcontext + editingContext: (EOEditingContext *)ec; + +- initWithGlobalID: (EOKeyGlobalID *)globalID + databaseContext: (EODatabaseContext *)dbcontext + editingContext: (EOEditingContext *)ec; + +- (EOKeyGlobalID *)globalID; +- (EODatabaseContext *)databaseContext; +- (EOEditingContext *)editingContext; + +@end + + +@interface EOAccessArrayFaultHandler:EOAccessGenericFaultHandler +{ + EOKeyGlobalID *sgid; + NSString *relationshipName; + EODatabaseContext *databaseContext; + EOEditingContext *editingContext; + id copy; +} + ++ (EOAccessArrayFaultHandler *)accessArrayFaultHandlerWithSourceGlobalID: (EOKeyGlobalID *)sourceGID + relationshipName: (NSString *)relationshipName + databaseContext: (EODatabaseContext *)dbcontext + editingContext: (EOEditingContext *)ec; + +- initWithSourceGlobalID: (EOKeyGlobalID *)sourceGID + relationshipName: (NSString *)relationshipName + databaseContext: (EODatabaseContext *)dbcontext + editingContext: (EOEditingContext *)ec; + +- (EOKeyGlobalID *)sourceGlobalID; +- (NSString *)relationshipName; +- (EODatabaseContext *)databaseContext; +- (EOEditingContext *)editingContext; + +@end + + +@interface NSObject (EOAccessFaultUnableToFaultToOne) + +- (void)unableToFaultObject:(id)object + databaseContext:(EODatabaseContext *)context; + +@end + + +extern NSString *EOAccessFaultObjectNotAvailableException; + + +#endif diff --git a/EOAccess/EOAccessFault.m b/EOAccess/EOAccessFault.m new file mode 100644 index 0000000..8ccc88c --- /dev/null +++ b/EOAccess/EOAccessFault.m @@ -0,0 +1,324 @@ +/** + EOAccessFault.m EOAccessFault Class + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: June 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import + +#import +#import +#import + +#import + + +NSString *EOAccessFaultObjectNotAvailableException = @"EOAccessFaultObjectNotAvailableException"; + + +@implementation EOAccessGenericFaultHandler + +- (void)linkAfter: (EOAccessGenericFaultHandler *)faultHandler + usingGeneration: (unsigned int)gen +{ + _generation = gen; + + _prev = faultHandler; + _next = faultHandler->_next; + + faultHandler->_next = self; + + if(_next) + _next->_prev = self; +} + +- (void)_linkNext: (EOAccessGenericFaultHandler *)next +{ + if(_next) + _next->_prev = nil; + + _next = next; + + if(next) + next->_prev = self; +} + +- (void)_linkPrev: (EOAccessGenericFaultHandler *)prev +{ + if(_prev) + _prev->_next = nil; + + _prev = prev; + + if(prev) + prev->_next = self; +} + +- (EOAccessGenericFaultHandler *)next +{ + return _next; +} + +- (EOAccessGenericFaultHandler *)previous +{ + return _prev; +} + +- (unsigned int)generation +{ + return _generation; +} + +- (void)faultWillFire: (id)object +{ +//TODO change le prev, met à 0 +} + +@end + + + +@implementation EOAccessFaultHandler + +- (id) init +{ + if ((self = [super init])) + { + } + + return self; +} + ++ (EOAccessFaultHandler *)accessFaultHandlerWithGlobalID: (EOKeyGlobalID *)globalID + databaseContext: (EODatabaseContext *)dbcontext + editingContext: (EOEditingContext *)ec +{ + return [[[self alloc] initWithGlobalID: globalID + databaseContext: dbcontext + editingContext: ec] autorelease]; +} + +- (id) initWithGlobalID: (EOKeyGlobalID *)globalID + databaseContext: (EODatabaseContext *)dbcontext + editingContext: (EOEditingContext *)ec +{ + if ((self = [self init])) + { + EOFLOGObjectFnStartOrCond(@"EOAccesFaultHandler"); + + ASSIGNCOPY(gid, globalID); + ASSIGN(databaseContext, dbcontext); + ASSIGN(editingContext, ec); + } + + return self; +} + +- (void)dealloc +{ + EOFLOGObjectFnStopOrCond(@"EOAccesFaultHandler"); + + DESTROY(gid); + DESTROY(databaseContext); + DESTROY(editingContext); +} + +- (EOKeyGlobalID *)globalID +{ +#ifdef DEBUG + EOFLOGObjectFnStartOrCond(@"EOAccesFaultHandler"); + EOFLOGObjectFnStopOrCond(@"EOAccesFaultHandler"); +#endif + + return gid; +} + +- (EODatabaseContext *)databaseContext +{ + return databaseContext; +} + +- (EOEditingContext *)editingContext +{ + return editingContext; +} + +- (void)completeInitializationOfObject:(id)anObject +{ + EOFLOGObjectFnStart(); + + [databaseContext _fireFault: anObject]; + +//MIRKO: replaced +/* + [databaseContext _batchToOne:anObject + withHandler:self]; +*/ + + if ([EOFault isFault: anObject] == YES) + { + NSDebugMLLog(@"error", @"UnableToFaultObject: %p of class %@", + anObject, + [EOFault targetClassForFault: anObject]); + [self unableToFaultObject: anObject + databaseContext: databaseContext]; + } + + EOFLOGObjectFnStop(); +} + +- (BOOL)shouldPerformInvocation: (NSInvocation *)invocation +{ + return YES; +} + +@end + + +@implementation NSObject (EOAccessFaultUnableToFaultToOne) + +- (void)unableToFaultObject: (id)object + databaseContext: (EODatabaseContext *)context +{ + EOFaultHandler *handler = [EOFault handlerForFault:object]; + EOGlobalID *globalID = nil; + + if ([handler respondsToSelector: @selector(globalID)]) + globalID = [(EOAccessFaultHandler *)handler globalID]; + + NSDebugMLLog(@"gsdb", @"Fault Handler=%@ (%@)", handler, [handler class]); + + [NSException raise: EOAccessFaultObjectNotAvailableException + format: @"%@ -- %@ 0x%x: cannot fault to-one for object %@ of class %@ databaseContext %@ handler %@ (globalID=%@)", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + object, + [EOFault targetClassForFault: object], + context, + handler, + globalID]; +} + +@end + + +@implementation EOAccessArrayFaultHandler + ++ (EOAccessArrayFaultHandler *)accessArrayFaultHandlerWithSourceGlobalID: (EOKeyGlobalID *)sourceGID + relationshipName: (NSString *)aRelationshipName + databaseContext: (EODatabaseContext *)dbcontext + editingContext: (EOEditingContext *)ec +{ + return [[[self alloc] initWithSourceGlobalID: sourceGID + relationshipName: aRelationshipName + databaseContext: dbcontext + editingContext: ec] autorelease]; +} + +- initWithSourceGlobalID: (EOKeyGlobalID *)sourceGID + relationshipName: (NSString *)relName + databaseContext: (EODatabaseContext *)dbcontext + editingContext: (EOEditingContext *)ec +{ + if ((self = [self init])) + { + ASSIGN(sgid, sourceGID); + ASSIGN(relationshipName, relName); + ASSIGN(databaseContext, dbcontext); + ASSIGN(editingContext, ec); + } + + return self; +} + +- (void)dealloc +{ + DESTROY(sgid); + DESTROY(relationshipName); + DESTROY(databaseContext); + DESTROY(editingContext); + + [super dealloc]; +} + +- (EOKeyGlobalID *)sourceGlobalID +{ + return sgid; +} + +- (NSString *)relationshipName +{ + return relationshipName; +} + +- (EODatabaseContext *)databaseContext +{ + return databaseContext; +} + +- (EOEditingContext *)editingContext +{ + return editingContext; +} + +- (void)completeInitializationOfObject: (id)anObject +{ + EOFLOGObjectFnStart(); + + [databaseContext _fireArrayFault: anObject]; + [(EOCheapCopyMutableArray *)anObject _setCopy: NO]; + + NSDebugMLLog(@"gsdb", @"anObject %p=%@", anObject, anObject); + EOFLOGObjectFnStop(); + +/*MIRKO replaced + [databaseContext _batchToMany:anObject + withHandler:self]; +*/ +} + +- (id) descriptionForObject: (id)object +{ + //OK + return [NSString stringWithFormat: @"", + object, + sgid, + relationshipName]; +} + +- (BOOL)shouldPerformInvocation: (NSInvocation *)invocation +{ + return YES; +} + +@end diff --git a/EOAccess/EOAccessFaultPriv.h b/EOAccess/EOAccessFaultPriv.h new file mode 100644 index 0000000..4c194f6 --- /dev/null +++ b/EOAccess/EOAccessFaultPriv.h @@ -0,0 +1,37 @@ +/* + EOAccessFaultPriv.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: July 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOAccessFaultPriv_h__ +#define __EOAccessFaultPriv_h__ + +@interface EOAccessGenericFaultHandler (EOAccessFaultPrivate) + +- (void)_linkNext: (EOAccessGenericFaultHandler *)next; +- (void)_linkPrev: (EOAccessGenericFaultHandler *)prev; + +@end + +#endif diff --git a/EOAccess/EOAdaptor.h b/EOAccess/EOAdaptor.h new file mode 100644 index 0000000..fca6d1a --- /dev/null +++ b/EOAccess/EOAdaptor.h @@ -0,0 +1,172 @@ +/* + EOAdaptor.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOAdaptor_h__ +#define __EOAdaptor_h__ + +#import + + +@class NSMutableArray; +@class NSDictionary; +@class NSString; +@class NSNumber; + +@class EOModel; +@class EOAttribute; +@class EOAdaptorContext; +@class EOLoginPanel; +@class EOEntity; + +extern NSString *EOGeneralAdaptorException; + + +@interface EOAdaptor : NSObject +{ + EOModel *_model;//Not in EOFD + + NSString *_name; + NSDictionary *_connectionDictionary; + NSMutableArray *_contexts; // values with contexts + NSString *_expressionClassName; + Class _expressionClass; + id _delegate; // not retained + + struct { + unsigned processValue:1; + } _delegateRespondsTo; +} + +/* Creating an EOAdaptor */ ++ (EOAdaptor *)adaptorWithModel: (EOModel *)model; ++ (EOAdaptor *)adaptorWithName: (NSString *)name; + ++ (void)setExpressionClassName: (NSString *)sqlExpressionClassName + adaptorClassName: (NSString *)adaptorClassName; ++ (EOLoginPanel *)sharedLoginPanelInstance; + ++ (NSArray *)availableAdaptorNames; ++ (NSArray *)prototypes; + +- initWithName:(NSString *)name; + +/* Getting an adaptor's name */ +- (NSString *)name; + +/* Creating and removing an adaptor context */ +- (EOAdaptorContext *)createAdaptorContext; +- (NSArray *)contexts; + +/* Setting the model */ +- (void)setModel: (EOModel*)aModel;//Not in EOFD +- (EOModel*)model;//Not in EOFD + +/* Checking connection status */ +- (BOOL)hasOpenChannels; + +/* Getting adaptor-specific information */ +- (Class)expressionClass; +- (Class)defaultExpressionClass; + +/* Reconnection to database */ +- (void)handleDroppedConnection; +- (BOOL)isDroppedConnectionException: (NSException *)exception; + +/* Setting connection information */ +- (void)setConnectionDictionary: (NSDictionary*)aDictionary; +- (NSDictionary *)connectionDictionary; +- (void)assertConnectionDictionaryIsValid; + +- (BOOL)canServiceModel: (EOModel *)model; + +- (NSStringEncoding)databaseEncoding; + +- (id)fetchedValueForValue: (id)value + attribute: (EOAttribute *)attribute; +- (NSString *)fetchedValueForStringValue: (NSString *)value + attribute: (EOAttribute *)attribute; +- (NSNumber *)fetchedValueForNumberValue: (NSNumber *)value + attribute: (EOAttribute *)attribute; +- (NSCalendarDate *)fetchedValueForDateValue: (NSCalendarDate *)value + attribute: (EOAttribute *)attribute; +- (NSData *)fetchedValueForDataValue: (NSData *)value + attribute: (EOAttribute *)attribute; + +/* Setting the delegate */ +- (id)delegate; +- (void)setDelegate: delegate; + +@end /* EOAdaptor */ + + +@interface EOAdaptor (EOAdaptorLoginPanel) + +- (BOOL)runLoginPanelAndValidateConnectionDictionary; +- (NSDictionary *)runLoginPanel; + +@end + + +@interface EOAdaptor (EOExternalTypeMapping) + ++ (NSString *)internalTypeForExternalType: (NSString *)extType + model: (EOModel *)model; ++ (NSArray *)externalTypesWithModel: (EOModel *)model; ++ (void)assignExternalTypeForAttribute: (EOAttribute *)attribute; ++ (void)assignExternalInfoForAttribute: (EOAttribute *)attribute; ++ (void)assignExternalInfoForEntity: (EOEntity *)entity; ++ (void)assignExternalInfoForEntireModel: (EOModel *)model; + +@end + + +@interface EOAdaptor (EOSchemaGenerationExtensions) + +- (void)dropDatabaseWithAdministrativeConnectionDictionary: (NSDictionary *)administrativeConnectionDictionary; +- (void)createDatabaseWithAdministrativeConnectionDictionary: (NSDictionary *)administrativeConnectionDictionary; + +@end + + +@interface EOLoginPanel : NSObject + +- (NSDictionary *)runPanelForAdaptor: (EOAdaptor *)adaptor validate: (BOOL)yn; +- (NSDictionary *)administraticeConnectionDictionaryForAdaptor: (EOAdaptor *)adaptor; + +@end + + +@interface NSObject (EOAdaptorDelegate) + +- (id)adaptor: (EOAdaptor *)adaptor +fetchedValueForValue: (id)value + attribute: (EOAttribute *)attribute; +- (NSDictionary *)reconnectionDictionaryForAdaptor: (EOAdaptor *)adaptor; + +@end /* NSObject (EOAdaptorDelegate) */ + + +#endif /* __EOAdaptor_h__*/ diff --git a/EOAccess/EOAdaptor.m b/EOAccess/EOAdaptor.m new file mode 100644 index 0000000..2b16b2a --- /dev/null +++ b/EOAccess/EOAdaptor.m @@ -0,0 +1,719 @@ +/** + EOAdaptor.m EOAdaptor Class + + Copyright (C) 1996-2001 Free Software Foundation, Inc. + + Author: Ovidiu Predescu + Date: October 1996 + + Author: Mirko Viviani + Date: February 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#if HAVE_LIBC_H +# include +#else +#ifndef __WIN32__ +# include +#endif /* !__WIN32__ */ +#endif + +#import +#import +#import +#import +#import +#import +#import +#import + +#import +#import + +#import +#import +#import +#import +#import +#import +#import +#import + +#import + + +NSString *EOGeneralAdaptorException = @"EOGeneralAdaptorException"; + + +@implementation EOAdaptor + + ++ (id)adaptorWithModel: (EOModel *)model +{ + //OK + /* Check first to see if the adaptor class exists in the running program + by testing the existence of [_model adaptorClassName]. */ + EOAdaptor *adaptor = nil; + + if(!model) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: no model specified", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + else + { + NSString *adaptorName = [model adaptorName]; + + if (!adaptorName) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: no adaptor name in model named %@", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + [model name]]; + else + { + Class adaptorClass = NSClassFromString([NSString stringWithFormat: @"%@%@", adaptorName, @"Adaptor"]); + + if(adaptorClass) + adaptor = [[[adaptorClass alloc] initWithName: adaptorName] + autorelease]; + else + adaptor = [self adaptorWithName: adaptorName]; + + [adaptor setModel: model]; + [adaptor setConnectionDictionary: [model connectionDictionary]]; + } + } + + return adaptor; +} + ++ (id) adaptorWithName: (NSString *)adaptorName +{ + //OK + NSBundle *bundle = [NSBundle mainBundle]; + NSString *adaptorBundlePath; + NSMutableArray *paths; + Class adaptorClass; + NSString *adaptorClassName; + NSProcessInfo *pInfo; + NSDictionary *env; + NSMutableString *user, *local, *system; + int i, count; + + /* Check error */ + if ([adaptorName length] == 0) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: adaptor name can't be nil", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + + // append EOAdaptor + adaptorName = [adaptorName stringByAppendingString: @"EOAdaptor"]; + + /* Look in application bundle */ + adaptorBundlePath = [bundle pathForResource: adaptorName + ofType: @"framework"]; + // should be NSString *path=[NSBundle pathForLibraryResource:libraryResource type:@"framework" directory:@"Frameworks"]; ? + + /* Look in standard paths */ + if (!adaptorBundlePath) + { + /* + The path of where to search for the adaptor files + is based upon environment variables. + GDL_ADAPTORS_PATH + GNUSTEP_USER_ROOT + GNUSTEP_LOCAL_ROOT + GNUSTEP_SYSTEM_ROOT + */ + pInfo = [NSProcessInfo processInfo]; + env = [pInfo environment]; + paths = [NSMutableArray array]; + + user = [[[env objectForKey: @"GNUSTEP_USER_ROOT"] + mutableCopy] autorelease]; + [user appendString: @"/Libraries/Frameworks"]; + + if (user) + [paths addObject: user]; + + local = [[[env objectForKey: @"GNUSTEP_LOCAL_ROOT"] + mutableCopy] autorelease]; + [local appendString: @"/Libraries/Frameworks"]; + + if (local) + [paths addObject: local]; + + local = [[[env objectForKey: @"GNUSTEP_LOCAL_ROOT"] + mutableCopy] autorelease]; + [local appendString: @"/Library/Frameworks"]; + + if (local) + [paths addObject: local]; + + system = [[[env objectForKey: @"GNUSTEP_SYSTEM_ROOT"] + mutableCopy] autorelease]; + [system appendString: @"/Libraries/Frameworks"]; + + if (system) + [paths addObject: system]; + + /* Loop through the paths and check each one */ + for(i = 0, count = [paths count]; i < count; i++) + { + bundle = [NSBundle bundleWithPath: [paths objectAtIndex: i]]; + adaptorBundlePath = [bundle pathForResource: adaptorName + ofType: @"framework"]; + + if(adaptorBundlePath && [adaptorBundlePath length]) + break; + } + } + + /* Make adaptor bundle */ + if(adaptorBundlePath) + bundle = [NSBundle bundleWithPath: adaptorBundlePath]; + else + bundle = nil; + + /* Check bundle */ + if (!bundle) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: the adaptor bundle '%@' does not exist", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + adaptorName]; + + /* Get the adaptor bundle "infoDictionary", and pricipal class, ie. the + adaptor class. Other info about the adaptor should be put in the + bundle's "Info.plist" file (property list format - see NSBundle class + documentation for details about reserved keys in this dictionary + property list containing one entry whose key is adaptorClassName. It + identifies the actual adaptor class from the bundle. */ + + adaptorClass = [bundle principalClass]; //NSString* adaptorClassName=[infoDictionary objectForKey:@"EOAdaptorClassName"]; ?? + + if (adaptorClass == Nil) { + adaptorClassName = [[bundle infoDictionary] objectForKey: @"EOAdaptorClassName"]; + + NSLog(@"adaptorClassName is %@", adaptorClassName); + + adaptorClass = NSClassFromString(adaptorClassName); + } + + if(!adaptorClass) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: the adaptor bundle '%@' doesn't contain a principal class", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + adaptorName]; + + return [[[adaptorClass alloc] initWithName: adaptorName] autorelease]; +} + ++ (void)setExpressionClassName: (NSString *)sqlExpressionClassName + adaptorClassName: (NSString *)adaptorClassName +{ + // TODO + [self notImplemented: _cmd]; +} + ++ (EOLoginPanel *)sharedLoginPanelInstance +{ + // TODO + [self notImplemented: _cmd]; + return nil; +} + ++ (NSArray *)availableAdaptorNames +{ + NSArray *pathArray = NSStandardLibraryPaths(); + NSEnumerator *pathEnum = [pathArray objectEnumerator]; + NSString *searchPath; + NSFileManager *defaultManager = [NSFileManager defaultManager]; + NSArray *fileNames; + NSEnumerator *filesEnum; + NSString *fileName; + NSMutableArray *adaptorNames = [[NSMutableArray new] autorelease]; + + EOFLOGObjectFnStartOrCond2(@"AdaptorLevel", @"EOAdaptor"); + + while ((searchPath = [pathEnum nextObject])) + { + fileNames = [defaultManager + directoryContentsAtPath: + [searchPath stringByAppendingPathComponent:@"Frameworks"]]; + filesEnum = [fileNames objectEnumerator]; + + //NSLog(@"EOAdaptor : availableAdaptorNames, path = %@", searchPath); + + while ((fileName = [filesEnum nextObject])) + { + //NSLog(@"EOAdaptor : availableAdaptorNames, fileName = %@", fileName); + if ([fileName hasSuffix:@"EOAdaptor.framework"]) { + [adaptorNames addObject: + [fileName substringToIndex: + ([fileName length] + - [@"EOAdaptor.framework" length])]]; + } + } + } + + EOFLOGObjectFnStopOrCond2(@"AdaptorLevel", @"EOAdaptor"); + + return adaptorNames; +} + ++ (NSArray *)prototypes +{ + // TODO + [self notImplemented: _cmd]; + return nil; +} + +- initWithName:(NSString *)name +{ + if ((self = [super init])) + { + ASSIGN(_name, name); + _contexts = [NSMutableArray new]; + } + + return self; +} + +- (void)dealloc +{ + DESTROY(_model); + DESTROY(_name); + DESTROY(_connectionDictionary); + DESTROY(_contexts); + + [super dealloc]; +} + +- (void)setConnectionDictionary: (NSDictionary *)dictionary +{ + //OK + if ([self hasOpenChannels]) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: cannot set the connection dictionary while the adaptor is connected!", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + + ASSIGN(_connectionDictionary, dictionary); +// [model setConnectionDictionary:dictionary]; // TODO ?? +} + +- (void)assertConnectionDictionaryIsValid +{ + return; +} + +- (EOAdaptorContext *)createAdaptorContext +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +- (NSArray *)contexts +{ + return _contexts; +} + +- (BOOL)hasOpenChannels +{ + int i; + + for (i = [_contexts count] - 1; i >= 0; i--) + { + EOAdaptorContext *ctx = [[_contexts objectAtIndex: i] + nonretainedObjectValue]; + + if([ctx hasOpenChannels] == YES) + return YES; + } + + return NO; +} + +- (void)setDelegate:delegate +{ + _delegate = delegate; + + _delegateRespondsTo.processValue + = [delegate respondsToSelector: + @selector(adaptor:fetchedValueForValue:attribute:)]; +} + +- (void)setModel: (EOModel *)model +{ + ASSIGN(_model, model); +} + +- (NSString *)name +{ + return _name; +} + +- (NSDictionary *)connectionDictionary +{ + return _connectionDictionary; +} + +- (EOModel *)model +{ + return _model; +} + +- delegate +{ + return _delegate; +} + +- (Class)expressionClass +{ + Class expressionClass = Nil; + + EOFLOGObjectFnStart(); +/* retrieve EOAdaptorQuotesExternalNames from ? or from user default */ + + expressionClass = _expressionClass; + + if(!expressionClass) + expressionClass = [self defaultExpressionClass]; + + EOFLOGObjectFnStop(); + + return expressionClass; +} + +- (Class)defaultExpressionClass +{ + [self subclassResponsibility: _cmd]; + return Nil; //TODO vedere setExpressionClass +} + +- (BOOL)canServiceModel: (EOModel *)model +{ + return [_connectionDictionary isEqual: [model connectionDictionary]]; +} + +- (NSStringEncoding)databaseEncoding +{ + NSString *encodingString=nil; + NSDictionary *encodingsDict = [self connectionDictionary]; + NSStringEncoding *availableEncodingsArray; + int count = 0; + NSStringEncoding availableEncodingValue; + NSString *availableEncodingString; + + EOFLOGObjectFnStartOrCond2(@"AdaptorLevel",@"EOAdaptor"); + + if (encodingsDict + && (encodingString = [encodingsDict objectForKey: @"databaseEncoding"])) + { + availableEncodingsArray = [NSString availableStringEncodings]; + + while (availableEncodingsArray[count] != 0) + { + availableEncodingValue = availableEncodingsArray[count++]; + + availableEncodingString = (NSString *)GetEncodingName(availableEncodingValue); + + if (availableEncodingString) + { + if ([availableEncodingString isEqual: encodingString]) + { + EOFLOGObjectFnStopOrCond2(@"AdaptorLevel", @"EOAdaptor"); + + return availableEncodingValue; + } + } + } + } + + EOFLOGObjectFnStopOrCond2(@"AdaptorLevel", @"EOAdaptor"); + + return [NSString defaultCStringEncoding]; +} + +- (id)fetchedValueForValue: (id)value + attribute: (EOAttribute *)attribute +{ + //Should be OK + SEL valueFactoryMethod; + + EOFLOGObjectFnStart(); + NSDebugMLLog(@"gsdb", @"value=%@", value); + NSDebugMLLog(@"gsdb", @"attribute=%@", attribute); + + valueFactoryMethod = [attribute valueFactoryMethod]; + + if (valueFactoryMethod) + { + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + } + else + { + if ([value isKindOfClass: [NSString class]]) + [self fetchedValueForStringValue: value + attribute: attribute]; + else if ([value isKindOfClass: [NSNumber class]]) + value = [self fetchedValueForNumberValue: value + attribute: attribute]; + else if ([value isKindOfClass: [NSDate class]]) + value = [self fetchedValueForDateValue: value + attribute: attribute]; + else if ([value isKindOfClass: [NSData class]]) + value = [self fetchedValueForDataValue: value + attribute: attribute]; + + NSDebugMLLog(@"gsdb",@"value=%@",value); + } + + if(_delegateRespondsTo.processValue) + value = [_delegate adaptor: self + fetchedValueForValue: value + attribute: attribute]; + + NSDebugMLLog(@"gsdb", @"value=%@", value); + EOFLOGObjectFnStop(); + + return value; +} + +- (NSString *)fetchedValueForStringValue: (NSString *)value + attribute: (EOAttribute *)attribute +{ + NSString *resultValue = nil; + + EOFLOGObjectFnStart(); + NSDebugMLLog(@"gsdb", @"value=%@", value); + NSDebugMLLog(@"gsdb", @"attribute=%@", attribute); + + if([value length]>0) + { + //TODO-NOW: correct this code which loop! + /* + const char *cstr=NULL; + int i=0, spc=0; + cstr = [value cString]; + while(*cstr) + { + if(*cstr == ' ') + spc++; + else + spc = 0; + i++; + } + cstr = &cstr[-i]; + + if(!spc) + resultValue=value; + else if(!(&cstr[i-spc]-cstr)) + resultValue=nil; + else + resultValue=[NSString stringWithCString:cstr + length:&cstr[i-spc]-cstr]; + */ + resultValue = value; + } + + EOFLOGObjectFnStop(); + + return resultValue; +} + +- (NSNumber *)fetchedValueForNumberValue: (NSNumber *)value + attribute: (EOAttribute *)attribute +{ + return value; +} + +- (NSCalendarDate *)fetchedValueForDateValue: (NSCalendarDate *)value + attribute: (EOAttribute *)attribute +{ + return value; +} + +- (NSData *)fetchedValueForDataValue: (NSData *)value + attribute: (EOAttribute *)attribute +{ + return value; +} + +/* Reconnection to database */ +- (void)handleDroppedConnection +{ + NSDictionary *newConnectionDictionary = nil; + int i; + + for (i = [_contexts count] - 1; i >= 0; i--) + { + EOAdaptorContext *ctx = [[_contexts objectAtIndex:i] + nonretainedObjectValue]; + + [ctx handleDroppedConnection]; + } + + [_contexts removeAllObjects]; + + if (_delegate + && [_delegate + respondsToSelector: @selector(reconnectionDictionaryForAdaptor:)]) + { + if ((newConnectionDictionary = [_delegate + reconnectionDictionaryForAdaptor: self])) + { + [self setConnectionDictionary: newConnectionDictionary]; + } + } +} + +- (BOOL)isDroppedConnectionException: (NSException *)exception +{ + EOFLOGObjectFnStartOrCond2(@"AdaptorLevel", @"EOAdaptor"); + EOFLOGObjectFnStopOrCond2(@"AdaptorLevel", @"EOAdaptor"); + + return NO; +} + +//NOT in EOF +- (void)createDatabaseWithAdministrativeConnectionDictionary: (NSDictionary *)connectionDictionary +{ + [self notImplemented: _cmd]; +} + +//NOT in EOF +- (void)dropDatabaseWithAdministrativeConnectionDictionary: (NSDictionary *)connectionDictionary +{ + [self notImplemented: _cmd]; +} + +@end /* EOAdaptor */ + + +@implementation EOAdaptor (EOAdaptorLoginPanel) + +- (BOOL)runLoginPanelAndValidateConnectionDictionary +{ + // TODO + NSEmitTODO(); + return NO; +} + +- (NSDictionary *)runLoginPanel +{ + // TODO + [self notImplemented: _cmd]; + return nil; +} + +@end + + +@implementation EOAdaptor (EOExternalTypeMapping) + ++ (NSString *)internalTypeForExternalType: (NSString *)extType + model: (EOModel *)model +{ + [self subclassResponsibility: _cmd]; + return nil; +} + ++ (NSArray *)externalTypesWithModel: (EOModel *)model +{ + [self subclassResponsibility: _cmd]; + return nil; +} + ++ (void)assignExternalTypeForAttribute: (EOAttribute *)attribute +{ + return; +} + ++ (void)assignExternalInfoForAttribute: (EOAttribute *)attribute +{ + // TODO + NSEmitTODO(); + [self assignExternalTypeForAttribute: attribute]; +} + ++ (void)assignExternalInfoForEntity: (EOEntity *)entity +{ + // TODO + [self notImplemented: _cmd]; +} + ++ (void)assignExternalInfoForEntireModel: (EOModel *)model +{ + // TODO + [self notImplemented: _cmd]; +} + +@end + + +@implementation EOAdaptor (EOAdaptorPrivate) + +- (void) _requestConcreteImplementationForSelector: (SEL)param0 +{ + [self notImplemented: _cmd]; //TODO +} + +- (void) _unregisterAdaptorContext: (EOAdaptorContext*)adaptorContext +{ + int i = 0; + + for (i = [_contexts count] - 1; i >= 0; i--) + { + if ([[_contexts objectAtIndex: i] nonretainedObjectValue] + == adaptorContext) + { + [_contexts removeObjectAtIndex: i]; + break; + } + } +} + +- (void) _registerAdaptorContext: (EOAdaptorContext*)adaptorContext +{ + [_contexts addObject: [NSValue valueWithNonretainedObject: adaptorContext]]; +} + +@end diff --git a/EOAccess/EOAdaptorChannel.h b/EOAccess/EOAdaptorChannel.h new file mode 100644 index 0000000..78bcc67 --- /dev/null +++ b/EOAccess/EOAdaptorChannel.h @@ -0,0 +1,233 @@ +/* + EOAdaptorChannel.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOAdaptorChannel_h__ +#define __EOAdaptorChannel_h__ + +#import + +#import + +#import + + +@class NSArray; +@class NSMutableArray; +@class NSDictionary; +@class NSMutableDictionary; +@class NSString; +@class NSMutableString; +@class NSCalendarDate; + +@class EOModel; +@class EOEntity; +@class EOAttribute; +@class EOQualifier; +@class EOStoredProcedure; +@class EOAdaptorOperation; +@class EOSQLExpression; + +/* The EOAdaptorChannel class could be overriden for a concrete database + adaptor. You have to override only those methods marked in this header + with `override'. +*/ + +@interface EOAdaptorChannel : NSObject +{ + EOAdaptorContext *_context; + id _delegate; // not retained + + BOOL _debug; + + /* Flags used to check if the delegate responds to several messages */ + struct { + unsigned willPerformOperations:1; + unsigned didPerformOperations:1; + unsigned shouldSelectAttributes:1; + unsigned didSelectAttributes:1; + unsigned willFetchRow:1; + unsigned didFetchRow:1; + unsigned didChangeResultSet:1; + unsigned didFinishFetching:1; + unsigned shouldEvaluateExpression:1; + unsigned didEvaluateExpression:1; + unsigned shouldExecuteStoredProcedure:1; + unsigned didExecuteStoredProcedure:1; + unsigned shouldConstructStoredProcedureReturnValues:1; + unsigned shouldReturnValuesForStoredProcedure:1; + } _delegateRespondsTo; +} + ++ (EOAdaptorChannel *)adaptorChannelWithAdaptorContext: (EOAdaptorContext *)adaptorContext; + +/* Initializing an adaptor context */ +- initWithAdaptorContext: (EOAdaptorContext *)adaptorContext; + +/* Getting the adaptor context */ +- (EOAdaptorContext *)adaptorContext; + +/* Opening and closing a channel */ +- (BOOL)isOpen; +- (void)openChannel; +- (void)closeChannel; + +/* Modifying rows */ +- (void)insertRow: (NSDictionary *)row forEntity: (EOEntity *)entity; +- (void)updateValues: (NSDictionary *)values +inRowDescribedByQualifier: (EOQualifier *)qualifier + entity: (EOEntity *)entity; +- (unsigned)updateValues: (NSDictionary *)values + inRowsDescribedByQualifier: (EOQualifier *)qualifier + entity: (EOEntity *)entity; +- (void)deleteRowDescribedByQualifier: (EOQualifier *)qualifier + entity: (EOEntity *)entity; +- (unsigned)deleteRowsDescribedByQualifier: (EOQualifier *)qualifier + entity: (EOEntity *)entity; + +/* Fetching rows */ +- (void)selectAttributes: (NSArray *)attributes + fetchSpecification: (EOFetchSpecification *)fetchSpecification + lock: (BOOL)aLockFlag + entity: (EOEntity *)entity; + +- (void)lockRowComparingAttributes: (NSArray *)atts + entity: (EOEntity *)entity + qualifier: (EOQualifier *)qualifier + snapshot: (NSDictionary *)snapshot; + +- (void)evaluateExpression: (EOSQLExpression *)expression; + +- (BOOL)isFetchInProgress; + +- (NSArray *)describeResults; + +- (NSMutableDictionary *)fetchRowWithZone: (NSZone *)zone; + +- (void)setAttributesToFetch: (NSArray *)attributes; + +- (NSArray *)attributesToFetch; + +- (void)cancelFetch; + +- (NSDictionary *)primaryKeyForNewRowWithEntity: (EOEntity *)entity; + +- (NSArray *)describeTableNames; + +- (NSArray *)describeStoredProcedureNames; + +- (EOModel *)describeModelWithTableNames: (NSArray *)tableNames; + +- (void)addStoredProceduresNamed: (NSArray *)storedProcedureNames + toModel: (EOModel *)model; + +- (void)setDebugEnabled:(BOOL)yn; +- (BOOL)isDebugEnabled; + +- (id)delegate; +- (void)setDelegate:(id)delegate; + +- (NSMutableDictionary *)dictionaryWithObjects: (id *)objects + forAttributes: (NSArray *)attributes + zone: (NSZone *)zone; + +@end + + +@interface EOAdaptorChannel (EOStoredProcedures) + +- (void)executeStoredProcedure: (EOStoredProcedure *)storedProcedure + withValues: (NSDictionary *)values; +- (NSDictionary *)returnValuesForLastStoredProcedureInvocation; + +@end + + +@interface EOAdaptorChannel (EOBatchProcessing) + +- (void)performAdaptorOperation: (EOAdaptorOperation *)adaptorOperation; +- (void)performAdaptorOperations: (NSArray *)adaptorOperations; + +@end + + +@interface NSObject (EOAdaptorChannelDelegation) + +- (NSArray *)adaptorChannel: channel + willPerformOperations: (NSArray *)operations; + +- (NSException *)adaptorChannel: channel + didPerformOperations: (NSArray *)operations + exception: (NSException *)exception; + +- (BOOL)adaptorChannel: channel +shouldSelectAttributes: (NSArray *)attributes + fetchSpecification: (EOFetchSpecification *)fetchSpecification + lock: (BOOL)flag + entity: (EOEntity *)entity; + +- (void)adaptorChannel: channel + didSelectAttributes: (NSArray *)attributes + fetchSpecification: (EOFetchSpecification *)fetchSpecification + lock:(BOOL) flag + entity: (EOEntity *)entity; + +- (void)adaptorChannelWillFetchRow: channel; + +- (void)adaptorChannel: channel didFetchRow: (NSMutableDictionary *)row; + +- (void)adaptorChannelDidChangeResultSet: channel; + +- (void)adaptorChannelDidFinishFetching: channel; + +- (BOOL)adaptorChannel: channel + shouldEvaluateExpression: (EOSQLExpression *)expression; + +- (void)adaptorChannel: channel + didEvaluateExpression: (EOSQLExpression *)expression; + +- (NSDictionary *)adaptorChannel: channel + shouldExecuteStoredProcedure: (EOStoredProcedure *)procedure + withValues: (NSDictionary *)values; + +- (void)adaptorChannel: channel +didExecuteStoredProcedure: (EOStoredProcedure *)procedure + withValues: (NSDictionary *)values; + +- (NSDictionary *)adaptorChannelShouldConstructStoredProcedureReturnValues: channel; + +- (NSDictionary *)adaptorChannel: channel +shouldReturnValuesForStoredProcedure: (NSDictionary *)returnValues; + +@end /* NSObject(EOAdaptorChannelDelegation) */ + + +extern NSString *EOAdaptorOperationsKey; +extern NSString *EOFailedAdaptorOperationKey; +extern NSString *EOAdaptorFailureKey; +extern NSString *EOAdaptorOptimisticLockingFailure; + + +#endif /* __EOAdaptorChannel_h__ */ diff --git a/EOAccess/EOAdaptorChannel.m b/EOAccess/EOAdaptorChannel.m new file mode 100644 index 0000000..9579850 --- /dev/null +++ b/EOAccess/EOAdaptorChannel.m @@ -0,0 +1,609 @@ +/** + EOAdaptorChannel.m EOAdaptorChannel + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import + +#import +#import + +#import +#import + +#import +#import +#import +#import +#import +#import +#import +#import + +#import +#import + + +NSString *EOAdaptorOperationsKey = @"EOAdaptorOperationsKey"; +NSString *EOFailedAdaptorOperationKey = @"EOFailedAdaptorOperationKey"; +NSString *EOAdaptorFailureKey = @"EOAdaptorFailureKey"; +NSString *EOAdaptorOptimisticLockingFailure = @"EOAdaptorOptimisticLockingFailure"; + + +@implementation EOAdaptorChannel + ++ (EOAdaptorChannel *)adaptorChannelWithAdaptorContext: (EOAdaptorContext *)adaptorContext +{ + return [[[self alloc] initWithAdaptorContext: adaptorContext] autorelease]; +} + +- (id) initWithAdaptorContext: (EOAdaptorContext *)adaptorContext +{ + if ((self = [super init])) + { + ASSIGN(_context, adaptorContext); + [_context _channelDidInit: self]; //TODO it's _registerAdaptorChannel: + } + + return self; +} + +- (void)dealloc +{ + [_context _channelWillDealloc: self]; + DESTROY(_context); + + [super dealloc]; +} + +- (void)openChannel +{ + [self subclassResponsibility: _cmd]; +} + +- (void)closeChannel +{ + [self subclassResponsibility: _cmd]; +} + +- (void)insertRow: (NSDictionary *)row + forEntity: (EOEntity *)entity +{ + [self subclassResponsibility: _cmd]; +} + +- (void)updateValues: (NSDictionary *)row +inRowDescribedByQualifier: (EOQualifier *)qualifier + entity: (EOEntity *)entity +{ + int rows; + + rows = [self updateValues: row + inRowsDescribedByQualifier: qualifier + entity: entity]; + + if(rows != 1) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: updated %d rows", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + rows]; +} + +- (unsigned)updateValues: (NSDictionary *)values +inRowsDescribedByQualifier: (EOQualifier *)qualifier + entity: (EOEntity *)entity +{ + [self subclassResponsibility: _cmd]; + return 0; +} + +- (void)deleteRowDescribedByQualifier: (EOQualifier *)qualifier + entity: (EOEntity *)entity +{ + int rows = 0; + + rows = [self deleteRowsDescribedByQualifier: qualifier + entity: entity]; + + if (rows != 1) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: deleted %d rows", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + rows]; +} + +- (unsigned)deleteRowsDescribedByQualifier: (EOQualifier *)qualifier + entity: (EOEntity *)entity +{ + [self subclassResponsibility: _cmd]; + return 0; +} + +- (void)selectAttributes: (NSArray *)attributes + fetchSpecification: (EOFetchSpecification *)fetchSpecification + lock: (BOOL)flag + entity: (EOEntity *)entity +{ + [self subclassResponsibility: _cmd]; +} + +- (void)lockRowComparingAttributes: (NSArray *)attrs + entity: (EOEntity *)entity + qualifier: (EOQualifier *)qualifier + snapshot: (NSDictionary *)snapshot +{ + EOFetchSpecification *fetch = nil; + NSDictionary *row = nil; + NSEnumerator *attrsEnum = nil; + EOAttribute *attr = nil; + NSMutableArray *attributes = nil; + BOOL isEqual = YES; + + EOFLOGObjectFnStart(); + NSDebugMLLog(@"gsdb", @"attrs=%@", attrs); + NSDebugMLLog(@"gsdb", @"entity=%@", entity); + NSDebugMLLog(@"gsdb", @"qualifier=%@" ,qualifier); + NSDebugMLLog(@"gsdb", @"snapshot=%@", snapshot); + + if (attrs) + attributes = [[attrs mutableCopy] autorelease]; + + if(attributes == nil) + attributes = [NSMutableArray array]; + + [attributes removeObjectsInArray: [entity primaryKeyAttributes]]; + [attributes addObjectsFromArray: [entity primaryKeyAttributes]]; + + fetch = [EOFetchSpecification fetchSpecificationWithEntityName: [entity name] + qualifier: qualifier + sortOrderings: nil]; + + [self selectAttributes: attributes + fetchSpecification: fetch + lock: YES + entity: entity]; + + row = [self fetchRowWithZone: NULL]; + + NSDebugMLLog(@"gsdb", @"row=%@", row); + + if(row == nil || [self fetchRowWithZone: NULL] != nil) + { + [NSException raise: EOGeneralAdaptorException + format: @"%@ -- %@ 0x%x: cannot lock row for entity '%@' with qualifier: %@", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + [entity name], + qualifier]; + } + + attrsEnum = [attributes objectEnumerator]; + + while((attr = [attrsEnum nextObject])) + { + NSString *name; + + name = [attr name]; + if([[row objectForKey: name] + isEqual: [snapshot objectForKey:name]] == NO) + { + isEqual = NO; + break; + } + } + + if(isEqual == NO) + { + [NSException raise: EOGeneralAdaptorException + format: @"%@ -- %@ 0x%x: cannot lock row for entity '%@' with qualifier: %@", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + [entity name], + qualifier]; + } + + EOFLOGObjectFnStop(); +} + +- (void)evaluateExpression: (EOSQLExpression *)expression +{ + [self subclassResponsibility: _cmd]; +} + +- (BOOL)isFetchInProgress +{ + [self subclassResponsibility: _cmd]; + return NO; +} + +- (NSArray *)describeResults +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +- (NSMutableDictionary *)fetchRowWithZone: (NSZone *)zone +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +- (void)setAttributesToFetch: (NSArray *)attributes +{ + [self subclassResponsibility: _cmd]; +} + +- (NSArray *)attributesToFetch +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +- (void)cancelFetch +{ + [self subclassResponsibility: _cmd]; +} + +- (NSDictionary *)primaryKeyForNewRowWithEntity: (EOEntity *)entity +{ + EOFLOGObjectFnStart(); + EOFLOGObjectFnStop(); + + return nil;//no or subclass respo ? +} + +- (NSArray *)describeTableNames +{ + return nil; +} + +- (NSArray *)describeStoredProcedureNames +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +- (EOModel *)describeModelWithTableNames: (NSArray *)tableNames +{ + return nil; +} + +- (void)addStoredProceduresNamed: (NSArray *)storedProcedureNames + toModel: (EOModel *)model +{ + [self subclassResponsibility: _cmd]; +} + +- (void)setDebugEnabled: (BOOL)flag +{ + _debug = flag; +} + +- (BOOL)isDebugEnabled +{ + return _debug; +} + +- delegate +{ + return _delegate; +} + +- (void)setDelegate:delegate +{ + _delegate = delegate; + + _delegateRespondsTo.willPerformOperations = + [_delegate respondsToSelector: + @selector(adaptorChannel:willPerformOperations:)]; + _delegateRespondsTo.didPerformOperations = + [_delegate respondsToSelector: + @selector(adaptorChannel:didPerformOperations:exception:)]; + _delegateRespondsTo.shouldSelectAttributes = + [_delegate respondsToSelector: + @selector(adaptorChannel:shouldSelectAttributes:fetchSpecification:lock:)]; + _delegateRespondsTo.didSelectAttributes = + [_delegate respondsToSelector: + @selector(adaptorChannel:didSelectAttributes:fetchSpecification:lock:)]; + _delegateRespondsTo.willFetchRow = + [_delegate respondsToSelector: + @selector(adaptorChannelWillFetchRow:)]; + _delegateRespondsTo.didFetchRow = + [_delegate respondsToSelector: + @selector(adaptorChannel:didFetchRow:)]; + _delegateRespondsTo.didChangeResultSet = + [_delegate respondsToSelector: + @selector(adaptorChannelDidChangeResultSet:)]; + _delegateRespondsTo.didFinishFetching = + [_delegate respondsToSelector: + @selector(adaptorChannelDidFinishFetching:)]; + _delegateRespondsTo.shouldEvaluateExpression = + [_delegate respondsToSelector: + @selector(adaptorChannel:shouldEvaluateExpression:)]; + _delegateRespondsTo.didEvaluateExpression = + [_delegate respondsToSelector: + @selector(adaptorChannel:didEvaluateExpression:)]; + _delegateRespondsTo.shouldExecuteStoredProcedure = + [_delegate respondsToSelector: + @selector(adaptorChannel:shouldExecuteStoredProcedure:withValues:)]; + _delegateRespondsTo.didExecuteStoredProcedure = + [_delegate respondsToSelector: + @selector(adaptorChannelDidExecuteStoredProcedure:withValues:)]; + _delegateRespondsTo.shouldConstructStoredProcedureReturnValues = + [_delegate respondsToSelector: + @selector(adaptorChannelShouldConstructStoredProcedureReturnValues:)]; + _delegateRespondsTo.shouldReturnValuesForStoredProcedure = + [_delegate respondsToSelector: + @selector(adaptorChannel:shouldReturnValuesForStoredProcedure:)]; +} + +- (NSMutableDictionary *)dictionaryWithObjects: (id *)objects + forAttributes: (NSArray *)attributes + zone: (NSZone *)zone +{ + //OK (can be improved by calling EOMutableKnownKeyDictionary iini with objects but the order may be different + EOMutableKnownKeyDictionary *dict=nil; + EOAttribute *anAttribute=[attributes firstObject]; + + NSAssert(anAttribute, @"No attribute"); + + if (anAttribute) + { + EOEntity *entity = [anAttribute entity]; + + NSAssert1(entity,@"No entity for attribute %@",anAttribute); + + if (entity) + { + NSArray *attributesToFetch = [entity _attributesToFetch]; + EOMKKDInitializer *initializer = [entity _adaptorDictionaryInitializer]; + int i = 0; + int count = [attributes count]; + + NSDebugMLLog(@"gsdb",@"\ndictionaryWithObjects:forAttributes:zone: attributes=%@ objects=%p\n",attributes,objects); + NSAssert(initializer,@"No initializer"); + + NSDebugMLLog(@"gsdb",@"initializer=%@",initializer); + + dict = [[[EOMutableKnownKeyDictionary allocWithZone: zone] + initWithInitializer:initializer] autorelease]; + + NSDebugMLLog(@"gsdb", @"dict=%@", dict); + + for(i = 0; i < count; i++) + { + EOAttribute *attribute = (EOAttribute *)[attributes objectAtIndex: i]; + + NSDebugMLLog(@"gsdb", @"Attribute=%@ value=%@", attribute, objects[i]); + + [dict setObject: objects[i] + forKey: [attribute name]]; + } + } + } + + return dict; +} + +- (EOAdaptorContext *)adaptorContext +{ + return _context; +} + +- (BOOL)isOpen +{ + [self subclassResponsibility: _cmd]; + return NO; +} + +@end /* EOAdaptorChannel */ + + +@implementation EOAdaptorChannel (EOStoredProcedures) + +- (void)executeStoredProcedure: (EOStoredProcedure *)storedProcedure + withValues: (NSDictionary *)values +{ + [self subclassResponsibility: _cmd]; +} + +- (NSDictionary *)returnValuesForLastStoredProcedureInvocation +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +@end + + +@implementation EOAdaptorChannel (EOBatchProcessing) + +- (void)performAdaptorOperation: (EOAdaptorOperation *)adaptorOperation +{ + EOAdaptorContext *adaptorContext = nil; + EOEntity *entity = nil; + EOAdaptorOperator operator; + NSDictionary *changedValues=nil; + + EOFLOGObjectFnStart(); + + adaptorContext = [self adaptorContext]; +//adaptorcontext transactionNestingLevel +//2fois +//... + + NSDebugMLLog(@"gsdb", @"adaptorOperation=%@", adaptorOperation); + + entity = [adaptorOperation entity]; + operator = [adaptorOperation adaptorOperator]; + changedValues = [adaptorOperation changedValues]; + + NSDebugMLLog(@"gsdb", @"ad op: %d %@", operator, [entity name]); + NSDebugMLLog(@"gsdb", @"ad op: %@ %@", [adaptorOperation changedValues], [adaptorOperation qualifier]); + + NS_DURING + switch(operator) + { + case EOAdaptorLockOperator: + NSDebugMLLog(@"gsdb", @"EOAdaptorLockOperator"); + + [self lockRowComparingAttributes: [adaptorOperation attributes] + entity: entity + qualifier: [adaptorOperation qualifier] + snapshot: changedValues]; + break; + + case EOAdaptorInsertOperator: + NSDebugMLLog(@"gsdb", @"EOAdaptorInsertOperator"); +/* +//self adaptorContext +//adaptorcontext transactionNestingLevel + NSArray* attributes=[entity attributes]; + + forech: externaltype +name + + PostgreSQLExpression initWithEntity: +//called from ??: expr setUseAliases:NO +prepareInsertExpressionWithRow:changedValues + [expr staement]; +*/ + [self insertRow: [adaptorOperation changedValues] + forEntity: entity]; + break; + + case EOAdaptorUpdateOperator: + NSDebugMLLog(@"gsdb", @"EOAdaptorUpdateOperator"); + //OK + [self updateValues: [adaptorOperation changedValues] + inRowDescribedByQualifier: [adaptorOperation qualifier] + entity: entity]; + break; + + case EOAdaptorDeleteOperator: + NSDebugMLLog(@"gsdb", @"EOAdaptorDeleteOperator"); + [self deleteRowDescribedByQualifier: [adaptorOperation qualifier] + entity: entity]; + break; + + case EOAdaptorStoredProcedureOperator: + NSDebugMLLog(@"gsdb", @"EOAdaptorStoredProcedureOperator"); + [self executeStoredProcedure: [adaptorOperation storedProcedure] + withValues: [adaptorOperation changedValues]]; + break; + + case EOAdaptorUndefinedOperator: + NSDebugMLLog(@"gsdb", @"EOAdaptorUndefinedOperator"); + + default: + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: Operator %d is not defined", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + (int)operator]; + break; + } + NS_HANDLER + { + NSDebugMLog(@"EXCEPTION %@", localException); + [adaptorOperation setException: localException]; + [localException raise]; + } + NS_ENDHANDLER; + +//end + + EOFLOGObjectFnStop(); +} + +- (void)performAdaptorOperations: (NSArray *)adaptorOperations +{ + int i = 0; + int count = 0; + + EOFLOGObjectFnStart(); + + count=[adaptorOperations count]; + + for(i = 0; i < count; i++) + { + EOAdaptorOperation *operation = [adaptorOperations objectAtIndex:i]; + + NS_DURING + [self performAdaptorOperation: operation]; + NS_HANDLER + { + NSException *exp = nil; + NSMutableDictionary *userInfo = nil; + EOAdaptorOperator operator = 0; + + NSDebugMLog(@"EXCEPTION %@", localException); + + operator = [operation adaptorOperator]; + + userInfo = [NSMutableDictionary dictionaryWithCapacity: 3]; + + [userInfo setObject: adaptorOperations + forKey: EOAdaptorOperationsKey]; + [userInfo setObject: operation + forKey: EOFailedAdaptorOperationKey]; + + if(operator == EOAdaptorLockOperator + || operator == EOAdaptorUpdateOperator) + [userInfo setObject: EOAdaptorOptimisticLockingFailure + forKey: EOAdaptorFailureKey]; + + exp = [NSException exceptionWithName: EOGeneralAdaptorException + reason: [NSString stringWithFormat:@"%@ -- %@ 0x%x: failed with exception name:%@ reason:\"%@\"", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + [localException name], + [localException reason]] + userInfo: userInfo]; + [exp raise]; + } + NS_ENDHANDLER; + } + + EOFLOGObjectFnStop(); +} + +@end diff --git a/EOAccess/EOAdaptorContext.h b/EOAccess/EOAdaptorContext.h new file mode 100644 index 0000000..9a53e2e --- /dev/null +++ b/EOAccess/EOAdaptorContext.h @@ -0,0 +1,135 @@ +/* + EOAdaptorContext.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOAdaptorContext_h__ +#define __EOAdaptorContext_h__ + +#import + +@class NSMutableArray; + +@class EOAdaptor; +@class EOAdaptorChannel; + +typedef enum { + EODelegateRejects, + EODelegateApproves, + EODelegateOverrides +} EODelegateResponse; + +/* The EOAdaptorContext class could be overriden for a concrete database + adaptor. You have to override only those methods marked in this header + with `override'. +*/ + +@interface EOAdaptorContext : NSObject +{ + EOAdaptor *_adaptor; + NSMutableArray *_channels; // values with channels + id _delegate; // not retained + + unsigned short _transactionNestingLevel; + BOOL _debug; + + /* Flags used to check if the delegate responds to several messages */ + struct { + unsigned shouldConnect:1; + unsigned shouldBegin:1; + unsigned didBegin:1; + unsigned shouldCommit:1; + unsigned didCommit:1; + unsigned shouldRollback:1; + unsigned didRollback:1; + } _delegateRespondsTo; +} + ++ (EOAdaptorContext *)adaptorContextWithAdaptor: (EOAdaptor *)adaptor; + +- initWithAdaptor: (EOAdaptor *)adaptor; + +- (EOAdaptor*)adaptor; + +- (EOAdaptorChannel *)createAdaptorChannel; // override + +- (BOOL)hasOpenChannels; +- (BOOL)hasBusyChannels; + +- delegate; +- (void)setDelegate:aDelegate; + +- (void)handleDroppedConnection; + +@end + + +@interface EOAdaptorContext (EOTransactions) + +- (void)beginTransaction; +- (void)commitTransaction; +- (void)rollbackTransaction; + +- (void)transactionDidBegin; +- (void)transactionDidCommit; +- (void)transactionDidRollback; + +- (BOOL)hasOpenTransaction; + +- (BOOL)canNestTransactions; // override +- (unsigned)transactionNestingLevel; + ++ (void)setDebugEnabledDefault: (BOOL)yn; ++ (BOOL)debugEnabledDefault; +- (void)setDebugEnabled: (BOOL)debugEnabled; +- (BOOL)isDebugEnabled; + +@end /* EOAdaptorContext (EOTransactions) */ + + +@interface EOAdaptorContext(Private) + +- (void)_channelDidInit: aChannel; +- (void)_channelWillDealloc: aChannel; + +@end + + +@interface NSObject (EOAdaptorContextDelegation) + +- (BOOL)adaptorContextShouldConnect: context; +- (BOOL)adaptorContextShouldBegin: context; +- (void)adaptorContextDidBegin: context; +- (BOOL)adaptorContextShouldCommit: context; +- (void)adaptorContextDidCommit: context; +- (BOOL)adaptorContextShouldRollback: context; +- (void)adaptorContextDidRollback: context; + +@end /* NSObject(EOAdaptorContextDelegate) */ + +extern NSString *EOAdaptorContextBeginTransactionNotification; +extern NSString *EOAdaptorContextCommitTransactionNotification; +extern NSString *EOAdaptorContextRollbackTransactionNotification; + +#endif /* __EOAdaptorContext_h__*/ diff --git a/EOAccess/EOAdaptorContext.m b/EOAccess/EOAdaptorContext.m new file mode 100644 index 0000000..85f8e91 --- /dev/null +++ b/EOAccess/EOAdaptorContext.m @@ -0,0 +1,277 @@ +/** + EOAdaptorContext.m EOAdaptorContext Class + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import +#import +#import +#import + +#import +#import +#import +#import + +NSString *EOAdaptorContextBeginTransactionNotification = @"EOAdaptorContextBeginTransactionNotofication"; +NSString *EOAdaptorContextCommitTransactionNotification = @"EOAdaptorContextCommitTransactionNotofication"; +NSString *EOAdaptorContextRollbackTransactionNotification = @"EOAdaptorContextRollbackTransactionNotofication"; + + +@implementation EOAdaptorContext + ++ (EOAdaptorContext *)adaptorContextWithAdaptor: (EOAdaptor *)adaptor +{ + return [[[self alloc] initWithAdaptor: adaptor] autorelease]; +} + +- (id) initWithAdaptor: (EOAdaptor *)adaptor +{ + if ((self = [super init])) + { + [adaptor _registerAdaptorContext: self]; + + ASSIGN(_adaptor, adaptor); + _channels = [NSMutableArray new]; + _transactionNestingLevel = 0; + + [self setDebugEnabled: [[self class] debugEnabledDefault]]; + } + + return self; +} + +- (void)dealloc +{ + [_adaptor _unregisterAdaptorContext: self]; + + DESTROY(_adaptor); + DESTROY(_channels); + + [super dealloc]; +} + +- (EOAdaptorChannel *)createAdaptorChannel +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +- (BOOL)hasOpenChannels +{ + int i, count = [_channels count]; + + for (i = 0; i < count; i++) + if ([[[_channels objectAtIndex: i] nonretainedObjectValue] isOpen]) + return YES; + + return NO; +} + +- (BOOL)hasBusyChannels +{ + int i, count = [_channels count]; + + for (i = 0; i < count; i++) + if ([[[_channels objectAtIndex: i] nonretainedObjectValue] + isFetchInProgress]) + return YES; + + return NO; +} + +- (void)setDelegate:delegate +{ + _delegate = delegate; + + _delegateRespondsTo.shouldConnect = + [delegate respondsToSelector:@selector(adaptorContextShouldConnect:)]; + _delegateRespondsTo.shouldBegin = + [delegate respondsToSelector:@selector(adaptorContextShouldBegin:)]; + _delegateRespondsTo.didBegin = + [delegate respondsToSelector:@selector(adaptorContextDidBegin:)]; + _delegateRespondsTo.shouldCommit = + [delegate respondsToSelector:@selector(adaptorContextShouldCommit:)]; + _delegateRespondsTo.didCommit = + [delegate respondsToSelector:@selector(adaptorContextDidCommit:)]; + _delegateRespondsTo.shouldRollback = + [delegate respondsToSelector:@selector(adaptorContextShouldRollback:)]; + _delegateRespondsTo.didRollback = + [delegate respondsToSelector:@selector(adaptorContextDidRollback:)]; +} + +- (EOAdaptor *)adaptor +{ + return _adaptor; +} + +- delegate +{ + return _delegate; +} + +- (void)handleDroppedConnection +{ + [self subclassResponsibility: _cmd]; +} + +@end + + +@implementation EOAdaptorContext (EOTransactions) + +- (void)beginTransaction +{ + [self subclassResponsibility: _cmd]; +} + +- (void)commitTransaction +{ + [self subclassResponsibility: _cmd]; +} + +- (void)rollbackTransaction +{ + [self subclassResponsibility: _cmd]; +} + +- (void)transactionDidBegin +{ + // Increment the transaction scope + _transactionNestingLevel++; + + [[NSNotificationCenter defaultCenter] + postNotificationName: EOAdaptorContextBeginTransactionNotification + object: self]; +//the notification call dbcontext _beginTransaction +} + +- (void)transactionDidCommit +{ + EOFLOGObjectFnStart(); + // Decrement the transaction scope + _transactionNestingLevel--;//OK + + //OK + [[NSNotificationCenter defaultCenter] + postNotificationName: EOAdaptorContextCommitTransactionNotification + object: self]; + + EOFLOGObjectFnStop(); +} + +- (void)transactionDidRollback +{ + // Decrement the transaction scope + _transactionNestingLevel--; + + [[NSNotificationCenter defaultCenter] + postNotificationName: EOAdaptorContextRollbackTransactionNotification + object: self]; +} + + - (BOOL)hasOpenTransaction + { + if (_transactionNestingLevel > 0) + return YES; + + return NO; + } + +- (BOOL)canNestTransactions +{ + [self subclassResponsibility: _cmd]; + return NO; +} + +- (unsigned)transactionNestingLevel +{ + return _transactionNestingLevel; +} + ++ (void)setDebugEnabledDefault: (BOOL)flag +{ + NSString *yn = (flag ? @"YES" : @"NO"); + + [[NSUserDefaults standardUserDefaults] setObject: yn + forKey: @"EOAdaptorDebugEnabled"]; +} + ++ (BOOL)debugEnabledDefault +{ + //OK + return [[NSUserDefaults standardUserDefaults] + boolForKey: @"EOAdaptorDebugEnabled"]; +} + +- (void)setDebugEnabled:(BOOL)debugEnabled +{ + _debug = debugEnabled; +} + +- (BOOL)isDebugEnabled +{ + return _debug; +} + +@end /* EOAdaptorContext (EOTransactions) */ + + +@implementation EOAdaptorContext (EOAdaptorContextPrivate) + +//_registerAdaptorChannel: +- (void)_channelDidInit: channel +{ + [_channels addObject: [NSValue valueWithNonretainedObject: channel]]; + + [channel setDebugEnabled: [self isDebugEnabled]]; +//call self delegate +//call channel setDelegate: returned ? +} + +- (void)_channelWillDealloc:channel +{ + int i; + + for (i = [_channels count] - 1; i >= 0; i--) + { + if ([[_channels objectAtIndex: i] nonretainedObjectValue] == channel) + { + [_channels removeObjectAtIndex: i]; + break; + } + } +} + +@end diff --git a/EOAccess/EOAdaptorOperation.m b/EOAccess/EOAdaptorOperation.m new file mode 100644 index 0000000..999fd19 --- /dev/null +++ b/EOAccess/EOAdaptorOperation.m @@ -0,0 +1,215 @@ +/** + EOAdaptorOperation.m EOAdaptorOperation Class + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import + +#import + +#import +#import +#import +#import + +#import + + +@implementation EOAdaptorOperation + ++ (EOAdaptorOperation *)adaptorOperationWithEntity: (EOEntity *)entity +{ + return [[[self alloc] initWithEntity: entity] autorelease]; +} + +- (id) initWithEntity: (EOEntity *)entity +{ + if ((self = [self init])) + { + ASSIGN(_entity, entity); + } + + return self; +} + +- (void)dealloc +{ + DESTROY(_entity); + DESTROY(_qualifier); + DESTROY(_changedValues); + DESTROY(_attributes); + DESTROY(_storedProcedure); + DESTROY(_exception); + + [super dealloc]; +} + +- (EOAdaptorOperator)adaptorOperator +{ + return _adaptorOperator; +} + +- (void)setAdaptorOperator: (EOAdaptorOperator)adaptorOperator +{ + NSDebugMLLog(@"gsdb", @"adaptorOperator=%d", adaptorOperator); + + _adaptorOperator = adaptorOperator; + + NSDebugMLLog(@"gsdb", @"_adaptorOperator=%d", _adaptorOperator); +} + +- (EOEntity *)entity +{ + return _entity; +} + +- (EOQualifier *)qualifier +{ + return _qualifier; +} + +- (void)setQualifier: (EOQualifier *)qualifier +{ + ASSIGN(_qualifier, qualifier); +} + +- (NSDictionary *)changedValues +{ + return _changedValues; +} + +- (void)setChangedValues: (NSDictionary *)changedValues +{ + ASSIGN(_changedValues, changedValues); +} + +- (NSArray *)attributes +{ + return _attributes; +} + +- (void)setAttributes: (NSArray *)attributes +{ + ASSIGN(_attributes, attributes); +} + +- (EOStoredProcedure *)storedProcedure +{ + return _storedProcedure; +} + +- (void)setStoredProcedure: (EOStoredProcedure *)storedProcedure +{ + ASSIGN(_storedProcedure, storedProcedure); +} + +- (NSException *)exception +{ + return _exception; +} + +- (void)setException: (NSException *)exception +{ + ASSIGN(_exception, exception); +} + +- (NSComparisonResult)compareAdaptorOperation: (EOAdaptorOperation *)adaptorOp +{ + NSComparisonResult res; + EOAdaptorOperator otherOp = [adaptorOp adaptorOperator]; + + res = [[_entity name] compare: [[adaptorOp entity] name]]; + + if(res == NSOrderedSame) + { + if(_adaptorOperator == otherOp) + res = NSOrderedSame; + else if(_adaptorOperator < otherOp) + res = NSOrderedAscending; + else + res = NSOrderedDescending; + } + + return res; +} + +- (NSString *)description +{ + //TODO revoir + NSString *operatorString = nil; + NSString *desc = nil; + + EOFLOGObjectFnStart(); + + switch(_adaptorOperator) + { + case EOAdaptorUndefinedOperator: + operatorString = @"EOAdaptorUndefinedOperator"; + break; + case EOAdaptorLockOperator: + operatorString = @"EOAdaptorLockOperator"; + break; + case EOAdaptorInsertOperator: + operatorString = @"EOAdaptorInsertOperator"; + break; + case EOAdaptorUpdateOperator: + operatorString = @"EOAdaptorUpdateOperator"; + break; + case EOAdaptorDeleteOperator: + operatorString = @"EOAdaptorDeleteOperator"; + break; + case EOAdaptorStoredProcedureOperator: + operatorString = @"EOAdaptorStoredProcedureOperator"; + break; + default: + operatorString = @"Unknwon"; + break; + } + + desc = [NSString stringWithFormat: @"<%s %p : operator: %@ entity: %@ qualifier:%@\nchangedValues: %@\nattributes:%@\nstoredProcedure: %@\nexception: %@>", + object_get_class_name(self), + (void*)self, + operatorString, + [_entity name], + _qualifier, + _changedValues, + _attributes, + _storedProcedure, + _exception]; + + EOFLOGObjectFnStop(); + + return desc; +} + +@end diff --git a/EOAccess/EOAdaptorPriv.h b/EOAccess/EOAdaptorPriv.h new file mode 100644 index 0000000..86e72ce --- /dev/null +++ b/EOAccess/EOAdaptorPriv.h @@ -0,0 +1,40 @@ +/* + EOAdaptorPriv.h + + Copyright (C) 2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: Nov 2002 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOAdaptorPriv_h__ +#define __EOAdaptorPriv_h__ + + +@interface EOAdaptor(EOAdaptorPrivate) + +- (void) _requestConcreteImplementationForSelector: (SEL)param0; +- (void) _unregisterAdaptorContext: (EOAdaptorContext*)adaptorContext; +- (void) _registerAdaptorContext: (EOAdaptorContext*)adaptorContext; + +@end + + +#endif /* __EOAdaptorPriv_h__ */ diff --git a/EOAccess/EOAttribute.h b/EOAccess/EOAttribute.h new file mode 100644 index 0000000..6e9cce0 --- /dev/null +++ b/EOAccess/EOAttribute.h @@ -0,0 +1,282 @@ +/* + EOAttribute.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: Feb 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOAttribute_h__ +#define __EOAttribute_h__ + +#import +#import +#import + +#import +#import +#import + +#import + + +@class EOEntity; +@class EOExpressionArray; +@class EOStoredProcedure; + + +typedef enum { + EOFactoryMethodArgumentIsNSData = 0, + EOFactoryMethodArgumentIsNSString, + EOFactoryMethodArgumentIsBytes +} EOFactoryMethodArgumentType; + +typedef enum { + EOAdaptorNumberType = 0, + EOAdaptorCharactersType, + EOAdaptorBytesType, + EOAdaptorDateType +} EOAdaptorValueType; + +typedef enum { + EOVoid = 0, + EOInParameter, + EOOutParameter, + EOInOutParameter +} EOParameterDirection; + + +@interface EOAttribute : GCObject +{ + NSString *_name; + NSString *_prototypeName; + NSString *_columnName; + NSString *_externalType; + NSString *_valueType; + NSString *_valueClassName; + NSString *_readFormat; + NSString *_writeFormat; + NSTimeZone *_serverTimeZone; + unsigned int _width; + unsigned short _precision; + short _scale; + Class _valueClass; + EOFactoryMethodArgumentType _argumentType; + NSString *_valueFactoryMethodName; + NSString *_adaptorValueConversionMethodName; + SEL _valueFactoryMethod; + SEL _adaptorValueConversionMethod; + struct { + unsigned int allowsNull:1; + unsigned int isReadOnly:1; + unsigned int isParentAnEOEntity:1; + unsigned int protoOverride:17; + unsigned int unused : 12; + unsigned int extraRefCount; + } _flags; + + NSDictionary *_sourceToDestinationKeyMap; + EOParameterDirection _parameterDirection; + NSDictionary *_userInfo; + NSDictionary *_internalInfo; + NSString *_docComment; + + /* Garbage collectable objects */ +// EOEntity *_entity; +// GCMutableArray *_definitionArray; // These variables are meaningful only + id _parent; + EOAttribute *_prototype; + EOExpressionArray *_definitionArray; + EOAttribute *_realAttribute; // if the attribute is flattened //Not in EOF ! +} + +/** returns an autoreleased attribute owned by onwer and built from propertyList **/ ++ (id) attributeWithPropertyList: (NSDictionary *)propertyList + owner: (id)owner; + +/* Accessing the entity */ +- (NSString *)name; + +- (EOEntity *)entity; + +- (EOStoredProcedure *)storedProcedure; + +- (id)parent; + +- (NSString *)prototypeName; +- (EOAttribute *)prototype; + +- (NSString *)externalType; + +- (NSString *)columnName; + +- (NSString *)definition; + +- (BOOL)isFlattened; + +- (BOOL)isDerived; + +- (BOOL)isReadOnly; + +- (NSString *)valueClassName; + +- (NSString *)valueType; + +- (unsigned)width; + +- (unsigned)precision; + +- (int)scale; + +- (BOOL)allowsNull; + +- (NSString *)writeFormat; +- (NSString *)readFormat; + +- (EOParameterDirection)parameterDirection; + +- (NSDictionary *)userInfo; + +- (NSString *)docComment; + +- (BOOL)isKeyDefinedByPrototype: (NSString *)key; + +@end + + +@interface EOAttribute (EOAttributeEditing) + +- (NSException *)validateName: (NSString *)name; + +- (void)setName: (NSString *)name; + +- (void)setPrototypeName: (NSString *)prototypeName; + +- (void)setReadOnly: (BOOL)yn; + +- (void)setColumnName: (NSString *)columnName; + +- (void)setDefinition: (NSString *)definition; + +- (void)setExternalType: (NSString *)type; + +- (void)setValueType: (NSString *)type; + +- (void)setValueClassName: (NSString *)name; + +- (void)setWidth: (unsigned)length; + +- (void)setPrecision: (unsigned)precision; + +- (void)setScale: (int)scale; + +- (void)setAllowsNull: (BOOL)allowsNull; + +- (void)setWriteFormat: (NSString *)string; + +- (void)setReadFormat: (NSString *)string; + +- (void)setParameterDirection: (EOParameterDirection)parameterDirection; + +- (void)setUserInfo: (NSDictionary *)dictionary; + +- (void)setInternalInfo: (NSDictionary *)dictionary; + +- (void)setDocComment: (NSString *)docComment; + +- (id)_normalizeDefinition: (EOExpressionArray*)definition + path: (id)path; + +@end + + +@interface EOAttribute(EOModelBeautifier) +- (void)beautifyName; +@end + +@interface EOAttribute (NSCalendarDateSupport) +- (NSTimeZone *)serverTimeZone; +@end + +@interface EOAttribute(NSCalendarDateSupportEditing) +- (void)setServerTimeZone: (NSTimeZone *)tz; +@end + + +@interface EOAttribute (EOAttributeValueCreation) + +- (id)newValueForBytes: (const void *)bytes + length: (int)length; + +- (id)newValueForBytes: (const void *)bytes + length: (int)length + encoding: (NSStringEncoding)encoding; + +- (NSCalendarDate *)newDateForYear: (int)year + month: (unsigned)month + day: (unsigned)day + hour: (unsigned)hour + minute: (unsigned)minute + second: (unsigned)second + millisecond: (unsigned)millisecond + timezone: (NSTimeZone *)timezone + zone: (NSZone *)zone; + +- (NSString *)valueFactoryMethodName; + +- (SEL)valueFactoryMethod; + +- (id)adaptorValueByConvertingAttributeValue: (id)value; + +- (NSString *)adaptorValueConversionMethodName; + +- (SEL)adaptorValueConversionMethod; + +- (EOAdaptorValueType)adaptorValueType; + +- (EOFactoryMethodArgumentType)factoryMethodArgumentType; + +@end + + +@interface EOAttribute(EOAttributeValueCreationEditing) + +- (void)setValueFactoryMethodName: (NSString *)factoryMethodName; + +- (void)setAdaptorValueConversionMethodName: (NSString *)conversionMethodName; + +- (void)setFactoryMethodArgumentType: (EOFactoryMethodArgumentType)argumentType; + +@end + +@interface EOAttribute(EOAttributeValueMapping) +- (NSException *)validateValue: (id *)valueP; +@end + + +@interface NSObject (EOCustomClassArchiving) + ++ objectWithArchiveData: (NSData *)data; +- (NSData *)archiveData; + +@end + +#endif /* __EOAttribute_h__ */ diff --git a/EOAccess/EOAttribute.m b/EOAccess/EOAttribute.m new file mode 100644 index 0000000..a082d61 --- /dev/null +++ b/EOAccess/EOAttribute.m @@ -0,0 +1,1285 @@ +/** + EOAttribute.m EOAttribute Class + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + Author: Manuel Guesdon + Date: October 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import + +#import +#import +#import +#import +#import + +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#import +#import + +@implementation EOAttribute + +static NSString *defaultCalendarFormat = @"%b %d %Y %H:%M"; + ++ (id) attributeWithPropertyList: (NSDictionary *)propertyList + owner: (id)owner +{ + return [[[self alloc] initWithPropertyList: propertyList + owner: owner] autorelease]; +} + +- (id) initWithPropertyList: (NSDictionary *)propertyList + owner: (id)owner +{ + if ((self = [self init])) + { + //OK + NSString *tmpString; + id tmpObject = nil; + + [self setName: [propertyList objectForKey: @"name"]]; + + NSDebugMLLog(@"gsdb", @"Attribute parent=%p %@", + owner, [(EOEntity *)owner name]); + + [self setParent: owner]; +// NSDebugMLLog(@"gsdb", @"Attribute Entity=%@", [self entity]); + + tmpString = [propertyList objectForKey: @"prototypeName"]; + if (tmpString) + [self setPrototypeName: tmpString]; + + [self setExternalType: [propertyList objectForKey: @"externalType"]]; + + tmpString = [propertyList objectForKey: @"allowsNull"]; + if (tmpString) + [self setAllowsNull: [tmpString isEqual: @"Y"]]; + + [self setValueType: [propertyList objectForKey: @"valueType"]]; + [self setValueClassName: [propertyList objectForKey: @"valueClassName"]]; + + tmpString = [propertyList objectForKey: @"writeFormat"]; + if (tmpString) + [self setWriteFormat: tmpString]; + else + { + tmpString = [propertyList objectForKey: @"updateFormat"]; + if (tmpString) + [self setWriteFormat: tmpString]; + else + { + tmpString = [propertyList objectForKey: @"insertFormat"]; + if (tmpString) + [self setWriteFormat: tmpString]; + } + } + + tmpString = [propertyList objectForKey: @"readFormat"]; + if (tmpString) + [self setReadFormat: tmpString]; + else + { + tmpString = [propertyList objectForKey: @"selectFormat"]; + [self setReadFormat: tmpString]; + } + + /* + tmpString = [propertyList objectForKey: @"maximumLength"]; + if (tmpString) + [self setMaximumLength: [tmpString intValue]]; + */ + + tmpString = [propertyList objectForKey: @"width"]; + if (tmpString) + [self setWidth: [tmpString intValue]]; + + tmpString = [propertyList objectForKey: @"valueFactoryMethodName"]; + if (tmpString) + [self setValueFactoryMethodName: tmpString]; + + tmpString = [propertyList objectForKey: @"adaptorValueConversionMethodName"]; + if (tmpString) + [self setAdaptorValueConversionMethodName: tmpString]; + + tmpString = [propertyList objectForKey: @"factoryMethodArgumentType"]; + if(tmpString) + { + EOFactoryMethodArgumentType argType = EOFactoryMethodArgumentIsBytes; + + if ([tmpString isEqual: @"EOFactoryMethodArgumentIsNSData"]) + argType = EOFactoryMethodArgumentIsNSData; + else if ([tmpString isEqual: @"EOFactoryMethodArgumentIsNSString"]) + argType = EOFactoryMethodArgumentIsNSString; + + [self setFactoryMethodArgumentType: argType]; + } + + tmpString = [propertyList objectForKey: @"precision"]; + if (tmpString) + [self setPrecision: [tmpString intValue]]; + + tmpString = [propertyList objectForKey: @"scale"]; + if (tmpString) + [self setScale: [tmpString intValue]]; + + tmpString = [propertyList objectForKey: @"serverTimeZone"]; + if (tmpString) + [self setServerTimeZone: [NSTimeZone timeZoneWithName: tmpString]]; + + tmpString = [propertyList objectForKey: @"parameterDirection"]; + if (tmpString) + { + EOParameterDirection eDirection = EOVoid; + + if ([tmpString isEqual: @"in"]) + eDirection = EOInParameter; + else if ([tmpString isEqual: @"out"]) + eDirection = EOOutParameter; + else if ([tmpString isEqual: @"inout"]) + eDirection = EOInOutParameter; + + [self setParameterDirection: eDirection]; + } + + tmpObject = [propertyList objectForKey: @"userInfo"]; + + if (tmpObject) + [self setUserInfo: tmpObject]; + else + { + tmpObject = [propertyList objectForKey: @"userDictionary"]; + + if (tmpObject) + [self setUserInfo: tmpObject]; + } + + tmpObject = [propertyList objectForKey: @"internalInfo"]; + + if (tmpObject) + [self setInternalInfo: tmpObject]; + + tmpString = [propertyList objectForKey: @"docComment"]; + + if (tmpString) + [self setDocComment: tmpString]; + + NSDebugMLLog(@"gsdb", @"Attribute name=%@", _name); + + tmpString = [propertyList objectForKey: @"isReadOnly"]; + NSDebugMLLog(@"gsdb", @"tmpString=%@", tmpString); + + [self setReadOnly: [tmpString isEqual: @"Y"]]; + NSDebugMLLog(@"gsdb", @"tmpString=%@", tmpString); + } + + return self; +} + +- (void)awakeWithPropertyList: (NSDictionary *)propertyList +{ + //Seems OK + NSString *definition = nil; + NSString *columnName = nil; + + definition = [propertyList objectForKey: @"definition"]; + + if (definition) + [self setDefinition: definition]; + + columnName = [propertyList objectForKey: @"columnName"]; + + if (columnName) + [self setColumnName: columnName]; + + NSDebugMLLog(@"gsdb", @"Attribute %@ awakeWithPropertyList:%@", self, propertyList); +} + +- (void)encodeIntoPropertyList: (NSMutableDictionary *)propertyList +{ + if (_name) + [propertyList setObject: _name forKey: @"name"]; + if (_serverTimeZone) + [propertyList setObject: [_serverTimeZone timeZoneName] + forKey: @"serverTimeZone"]; + if (_columnName) + [propertyList setObject: _columnName forKey: @"columnName"]; + if (_definitionArray) + [propertyList setObject: [_definitionArray definition] + forKey: @"definition"]; + if (_externalType) + [propertyList setObject: _externalType forKey: @"externalType"]; + if (_valueClassName) + [propertyList setObject: _valueClassName forKey: @"valueClassName"]; + if (_valueType) + [propertyList setObject: _valueType forKey: @"valueType"]; + if (_readFormat) + [propertyList setObject: _readFormat forKey: @"readFormat"]; + if (_writeFormat) + [propertyList setObject: _writeFormat forKey: @"writeFormat"]; + if (_userInfo) + [propertyList setObject: _userInfo forKey: @"userInfo"]; + if (_docComment) + [propertyList setObject: _docComment forKey: @"docComment"]; + + if (_flags.isReadOnly) + [propertyList setObject: [NSString stringWithCString: "Y"] + forKey: @"isReadOnly"]; +} + +- (void)dealloc +{ + DESTROY(_name); + DESTROY(_prototypeName); + DESTROY(_columnName); + DESTROY(_externalType); + DESTROY(_valueType); + DESTROY(_valueClassName); + DESTROY(_readFormat); + DESTROY(_writeFormat); + DESTROY(_serverTimeZone); + DESTROY(_valueFactoryMethodName); + DESTROY(_adaptorValueConversionMethodName); + DESTROY(_sourceToDestinationKeyMap); + DESTROY(_userInfo); + DESTROY(_internalInfo); + DESTROY(_docComment); + + [super dealloc]; +} + +- (void)gcDecrementRefCountOfContainedObjects +{ + EOFLOGObjectFnStart(); + + [_parent gcDecrementRefCount]; + NSDebugMLLog(@"gsdb", @"prototype gcDecrementRefCount"); + + [_prototype gcDecrementRefCount]; + NSDebugMLLog(@"gsdb", @"definitionArray gcDecrementRefCount"); + + [(id)_definitionArray gcDecrementRefCount]; + NSDebugMLLog(@"gsdb", @"realAttribute gcDecrementRefCount"); + + [_realAttribute gcDecrementRefCount]; + + EOFLOGObjectFnStop(); +} + +- (BOOL)gcIncrementRefCountOfContainedObjects +{ + if (![super gcIncrementRefCountOfContainedObjects]) + return NO; + + [_parent gcIncrementRefCount]; + [_prototype gcIncrementRefCount]; + [(id)_definitionArray gcIncrementRefCount]; + [_realAttribute gcIncrementRefCount]; + + [_parent gcIncrementRefCountOfContainedObjects]; + [_prototype gcIncrementRefCountOfContainedObjects]; + [(id)_definitionArray gcIncrementRefCountOfContainedObjects]; + [_realAttribute gcIncrementRefCountOfContainedObjects]; + + return YES; +} + +- (unsigned)hash +{ + return [_name hash]; +} + +- (NSString *)description +{ + NSString *dscr = [NSString stringWithFormat: @"<%s %p - name=%@ entity=%@ columnName=%@ definition=%@ ", + object_get_class_name(self), + (void*)self, + [self name], + [[self entity] name], + [self columnName], + [self definition]]; + + dscr = [dscr stringByAppendingFormat: @"valueClassName=%@ valueType=%@ externalType=%@ isReadOnly=%s isDerived=%s isFlattened=%s>", + [self valueClassName], + [self valueType], + [self externalType], + ([self isReadOnly] ? "YES" : "NO"), + ([self isDerived] ? "YES" : "NO"), + ([self isFlattened] ? "YES" : "NO")]; + + return dscr; +} + +- (EOEntity *)entity +{ + if (_flags.isParentAnEOEntity) + return _parent; + else + return nil; +} + +- (NSString *)name +{ + return _name; +} + +- (NSTimeZone *)serverTimeZone +{ + return _serverTimeZone; +} + +- (NSString *)columnName +{ + return _columnName; +} + +- (NSString *)definition +{ + NSString *definition = nil; + +// EOFLOGObjectFnStart(); +// NSDebugMLLog(@"gsdb",@"_definitionArray:%@",_definitionArray); + + definition=[_definitionArray valueForSQLExpression: nil]; + +// NSDebugMLLog(@"gsdb",@"definition:%@",definition); +// EOFLOGObjectFnStop(); + + return definition; +} + +- (NSString *)readFormat +{ + return _readFormat; +} + +- (NSString *)writeFormat +{ + return _writeFormat; +} + +- (NSDictionary *)userInfo +{ + return _userInfo; +} + +- (NSString *)docComment +{ + return _docComment; +} + +- (int)scale +{ + return _scale; +} + +- (unsigned)precision +{ + return _precision; +} + +- (unsigned)width +{ + return _width; +} + +- (id)parent +{ + return _parent; +} + +- (EOAttribute *)prototype +{ + return nil; // TODO +} + +- (NSString *)prototypeName +{ + return _prototypeName; +} + +- (EOParameterDirection)parameterDirection +{ + return _parameterDirection; +} + +- (BOOL)allowsNull +{ + return _flags.allowsNull; +} + +- (BOOL)isKeyDefinedByPrototype:(NSString *)key +{ + return NO; // TODO +} + +- (EOStoredProcedure *)storedProcedure +{ + if ([_parent isKindOfClass: [EOStoredProcedure class]]) + return _parent; + + return nil; +} + +- (BOOL)isReadOnly +{ +//call isDerived + return _flags.isReadOnly; +} + +/** Return NO when the attribute corresponds to one SQL column in its entity associated table return YES otherwise. +An attribute with a definition such as "anotherAttributeName * 2" is derived +A Flattened attribute is also a derived attributes. +**/ +- (BOOL)isDerived +{ + //Seems OK + if(_definitionArray) + return YES; + return NO; +} + + +/** Returns YES if the attribute is flattened, NO otherwise. +A flattened attribute is an attribute with a definition using a relationship to another entity +A Flattened attribute is also a derived attributes. +**/ + +- (BOOL)isFlattened +{ + BOOL isFlattened = NO; + // Seems OK + + if(_definitionArray) + isFlattened = [_definitionArray isFlattened]; + + return isFlattened; +} + +- (NSString *)valueClassName +{ + if (!_valueClassName && [self isFlattened]) + return [[_definitionArray realAttribute] valueClassName]; + + return _valueClassName; +} + +-(NSString *)externalType +{ + if (!_externalType && [self isFlattened]) + return [[_definitionArray realAttribute] externalType]; + + return _externalType; +} + +- (NSString *)valueType +{ + if(!_valueType && [self isFlattened]) + return [[_definitionArray realAttribute] valueType]; + + return _valueType; +} + +@end + +@implementation EOAttribute (EOAttributeSQLExpression) +/** Returns the value to use in an EOSQLExpression. **/ +- (NSString *) valueForSQLExpression: (EOSQLExpression *)sqlExpression +{ + NSString *value=nil; + +// NSDebugMLLog(@"gsdb",@"EOAttribute %p",self); + NSEmitTODO(); //TODO + + if (_definitionArray) + value = [_definitionArray valueForSQLExpression: sqlExpression]; + else + value = [self name]; + + return value; +} + +@end +@implementation EOAttribute (EOAttributeEditing) + +- (NSException *)validateName:(NSString *)name +{ + NSArray *storedProcedures; + const char *p, *s = [name cString]; + int exc = 0; + + if (!name || ![name length]) exc++; + + if (!exc) + { + p = s; + + while (*p) + { + if (!isalnum(*p) && + *p != '@' && *p != '#' && *p != '_' && *p != '$') + { + exc++; + break; + } + p++; + } + + if (!exc && *s == '$') + exc++; + + if ([[self entity] attributeNamed:name]) + exc++; + else if ([[self entity] relationshipNamed:name]) + exc++; + else if ((storedProcedures = [[[self entity] model] storedProcedures])) + { + NSEnumerator *stEnum = [storedProcedures objectEnumerator]; + EOStoredProcedure *st; + + while ((st = [stEnum nextObject])) + { + NSEnumerator *attrEnum; + EOAttribute *attr; + + attrEnum = [[st arguments] objectEnumerator]; + + while ((attr = [attrEnum nextObject])) + { + if ([name isEqualToString: [attr name]]) + { + exc++; + break; + } + } + + if (exc) break; + } + } + } + + if (exc) + return [NSException exceptionWithName: NSInvalidArgumentException + reason: [NSString stringWithFormat:@"%@ -- %@ 0x%x: argument \"%@\" contains invalid chars", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + name] + userInfo: nil]; + + return nil; +} + +- (void)setName: (NSString *)name +{ + [[self validateName: name] raise]; + + ASSIGN(_name, name); +} + +- (void)setPrototypeName: (NSString *)prototypeName +{ + ASSIGN(_prototypeName, prototypeName); +} + +- (void)setColumnName: (NSString *)columnName +{ + //seems OK + [self willChange]; + + ASSIGN(_columnName, columnName); + DESTROY(_definitionArray); + + [_parent _setIsEdited]; + [self _setOverrideForKeyEnum:1]; +} + +- (void)_setDefinitionWithoutFlushingCaches: (NSString *)definition +{ + EOExpressionArray *expressionArray=nil; + + [self willChange]; + expressionArray = [_parent _parseDescription: definition + isFormat: NO + arguments: NULL]; + + expressionArray = [self _normalizeDefinition: expressionArray + path: nil]; + /* + //TODO finish + l un est code + + entity primaryKeyAttributes (code) + ?? + + [self _removeFromEntityArray:code selector:setPrimaryKeyAttributes: + */ + + ASSIGN(_definitionArray, expressionArray); +} + +-(id)_normalizeDefinition: (EOExpressionArray*)definition + path: (id)path +{ +//TODO +/* +definition _isPropertyPath //NO +count +object atindex + self _normalizeDefinition:ret path:NSArray() +adddobject + + +if attribute +if isderived //NO +?? +ret attr + +return nexexp +*/ + return definition; +} + +- (void)setDefinition:(NSString *)definition +{ + if(definition) + { + [self _setDefinitionWithoutFlushingCaches: definition]; + [_parent _setIsEdited]; + DESTROY(_columnName);//?? + } +} + +- (void)setReadOnly: (BOOL)yn +{ + if(!yn && ([self isDerived] && ![self isFlattened])) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: cannot set to NO while the attribute is derived but not flattened.", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + + _flags.isReadOnly = yn; +} + +- (void)setExternalType: (NSString *)type +{ + //OK + [self willChange]; + + ASSIGN(_externalType, type); + + [_parent _setIsEdited]; + [self _setOverrideForKeyEnum: 0];//TODO +} + +- (void)setValueType: (NSString *)type +{ + //OK + [self willChange]; + + ASSIGN(_valueType, type); + + [self _setOverrideForKeyEnum: 4];//TODO +} + +- (void)setValueClassName: (NSString *)name +{ + //OK + [self willChange]; + + ASSIGN(_valueClassName, name); + + _valueClass = NSClassFromString(_valueClassName);//TODO Do it later ! + [self _setOverrideForKeyEnum: 3];//TODO +} + +- (void)setWidth: (unsigned)length +{ + _width = length; +} + +- (void)setPrecision: (unsigned)precision +{ + _precision = precision; +} + +- (void)setScale: (int)scale +{ + _scale = scale; +} + +- (void)setAllowsNull: (BOOL)allowsNull +{ + //OK + [self willChange]; + + _flags.allowsNull = allowsNull; + + [self _setOverrideForKeyEnum: 15];//TODO +} + +- (void)setWriteFormat: (NSString *)string +{ + ASSIGN(_writeFormat, string); +} + +- (void)setReadFormat: (NSString *)string +{ + ASSIGN(_readFormat, string); +} + +- (void)setParameterDirection: (EOParameterDirection)parameterDirection +{ + _parameterDirection = parameterDirection; +} + +- (void)setUserInfo: (NSDictionary *)dictionary +{ + //OK + [self willChange]; + + ASSIGN(_userInfo, dictionary); + + [_parent _setIsEdited]; + [self _setOverrideForKeyEnum: 10];//TODO +} + +- (void)setInternalInfo: (NSDictionary *)dictionary +{ + //OK + [self willChange]; + ASSIGN(_internalInfo, dictionary); + [_parent _setIsEdited]; + [self _setOverrideForKeyEnum: 10]; //TODO +} + +- (void)setDocComment: (NSString *)docComment +{ + //OK + [self willChange]; + ASSIGN(_docComment, docComment); + [_parent _setIsEdited]; +} + +@end + + +@implementation EOAttribute (EOBeautifier) + +/*+ Make the name conform to the Next naming style + NAME -> name, FIRST_NAME -> firstName +*/ +- (void)beautifyName +{ + NSArray *listItems; + NSString *newString=[NSMutableString string]; + int anz,i; + + EOFLOGObjectFnStartOrCond2(@"ModelingClasses", @"EOAttribute"); + + // Makes the receiver's name conform to a standard convention. Names that conform to this style are all lower-case except for the initial letter of each embedded word other than the first, which is upper case. Thus, "NAME" becomes "name", and "FIRST_NAME" becomes "firstName". + + if ((_name) && ([_name length]>0)) + { + listItems = [_name componentsSeparatedByString: @"_"]; + newString = [newString stringByAppendingString: + [[listItems objectAtIndex: 0] lowercaseString]]; + anz = [listItems count]; + + for(i = 1; i < anz; i++) + { + newString = [newString stringByAppendingString: + [[listItems objectAtIndex: i] + capitalizedString]]; + } + + //#warning ergÙnzen um alle components (attributes, ...) + + // Exception abfangen + NS_DURING + { + [self setName: newString]; + } + NS_HANDLER + { + NSLog(@"%@ in Class: EOAttribute , Method: beautifyName >> error : %@", + [localException name], [localException reason]); + } + NS_ENDHANDLER; + } + + EOFLOGObjectFnStopOrCond2(@"ModelingClasses", @"EOAttribute"); +} + +@end + + +@implementation EOAttribute (EOCalendarDateSupport) + +- (NSTimeZone *)serverTimeZone +{ + return _serverTimeZone; +} + +@end + + +@implementation EOAttribute (EOCalendarDateSupportEditing) + +- (void)setServerTimeZone: (NSTimeZone *)tz +{ + ASSIGN(_serverTimeZone, tz); +} + +@end + + +@implementation EOAttribute (EOAttributeValueCreation) + + +/** returns a NSString or a custom-class value object from the supplied set of bytes. +Adaptor call this method during value creation when fetching objects from the database. +For efficiency reasons, the returned value is NOT autoreleased ! +**/ +- (id)newValueForBytes: (const void *)bytes + length: (int)length +{ + NSMethodSignature *aSignature; + NSInvocation *anInvocation; + NSData *value = nil; + + if (_valueClass != Nil && _valueClass != [NSData class]) + { + switch (_argumentType) + { + case EOFactoryMethodArgumentIsNSData: + value = [[NSData alloc] initWithBytes:bytes length: length]; //For efficiency reasons, the returned value is NOT autoreleased ! + + if(_valueFactoryMethod != NULL) + value = [_valueClass performSelector: _valueFactoryMethod + withObject: [value autorelease]]; + break; + + case EOFactoryMethodArgumentIsBytes: + value = [_valueClass alloc];//For efficiency reasons, the returned value is NOT autoreleased ! + + aSignature = + [_valueClass + instanceMethodSignatureForSelector: _valueFactoryMethod]; + + anInvocation = [NSInvocation + invocationWithMethodSignature: aSignature]; + + [anInvocation setSelector: _valueFactoryMethod]; + [anInvocation setTarget: value]; + [anInvocation setArgument: &bytes atIndex: 2]; + [anInvocation setArgument: &length atIndex: 3]; + [anInvocation invoke]; + break; + + case EOFactoryMethodArgumentIsNSString: + break; + } + } + + if(!value) + value = [[NSData alloc] initWithBytes: bytes length: length];//For efficiency reasons, the returned value is NOT autoreleased ! + + return value; +} + +/** returns a NSString or a custom-class value object from the supplied set of bytes using encoding. +Adaptor call this method during value creation when fetching objects from the database. +For efficiency reasons, the returned value is NOT autoreleased ! +**/ +- (id)newValueForBytes: (const void *)bytes + length: (int)length + encoding: (NSStringEncoding)encoding +{ + NSMethodSignature *aSignature; + NSInvocation *anInvocation; + id value = nil; + + if (_valueClass != Nil && _valueClass != [NSString class]) + { + switch (_argumentType) + { + case EOFactoryMethodArgumentIsNSString: + value = [[NSString alloc] initWithData: [NSData dataWithBytes: bytes + length: length] + encoding: encoding];//For efficiency reasons, the returned value is NOT autoreleased ! + + value = [_valueClass performSelector: _valueFactoryMethod + withObject: [value autorelease]]; + break; + + case EOFactoryMethodArgumentIsBytes: + value = [_valueClass alloc];//For efficiency reasons, the returned value is NOT autoreleased ! + + aSignature = + [_valueClass + instanceMethodSignatureForSelector: _valueFactoryMethod]; + + anInvocation = [NSInvocation + invocationWithMethodSignature: aSignature]; + + [anInvocation setSelector: _valueFactoryMethod]; + [anInvocation setTarget: value]; + [anInvocation setArgument: &bytes atIndex: 2]; + [anInvocation setArgument: &length atIndex: 3]; + [anInvocation setArgument: &encoding atIndex: 4]; + [anInvocation invoke]; + break; + + case EOFactoryMethodArgumentIsNSData: + break; + } + } + + if(!value) + value = [[NSString alloc] + initWithData: [NSData dataWithBytes: bytes length: length] + encoding: encoding];//For efficiency reasons, the returned value is NOT autoreleased ! + + return value; +} + +/** +For efficiency reasons, the returned value is NOT autoreleased ! +**/ +- (NSCalendarDate *)newDateForYear: (int)year + month: (unsigned)month + day: (unsigned)day + hour: (unsigned)hour + minute: (unsigned)minute + second: (unsigned)second + millisecond: (unsigned)millisecond + timezone: (NSTimeZone *)timezone + zone: (NSZone *)zone +{ + NSCalendarDate *date; + + //For efficiency reasons, the returned value is NOT autoreleased ! + date = [[NSCalendarDate allocWithZone: zone] + initWithYear: year + month: month + day: day + hour: hour + minute: minute + second: second + timeZone: timezone]; + +// TODO milliseconds ?? + + return date; +} + +- (NSString *)valueFactoryMethodName +{ + return _valueFactoryMethodName; +} + +- (SEL)valueFactoryMethod +{ + return _valueFactoryMethod; +} + +- (id)adaptorValueByConvertingAttributeValue: (id)value +{ + id adaptorValue = nil; + SEL convMethod = NULL; + + convMethod = [self adaptorValueConversionMethod]; + + if (convMethod) + { + //TODO-VERIFY + adaptorValue = [value performSelector: convMethod]; + } + else + { + //TODO-VERIFY + EOAdaptorValueType adaptorValueType = [self adaptorValueType]; + + switch (adaptorValueType) + { + case EOAdaptorBytesType: + adaptorValue = [value archiveData]; + break; + + default: + if ([value isKindOfClass: [NSNumber class]] == YES || + [value isKindOfClass: [NSString class]] == YES || + [value isKindOfClass: [NSDate class]] == YES || + [value isKindOfClass: [NSData class]] == YES || + [value isKindOfClass: [[EONull null] class]] == YES) + adaptorValue = value; + else + adaptorValue = value; + break; + } + } + + return adaptorValue; +} + +- (NSString *)adaptorValueConversionMethodName +{ + return _adaptorValueConversionMethodName; +} + +- (SEL)adaptorValueConversionMethod +{ + return _adaptorValueConversionMethod; +} + +- (EOAdaptorValueType)adaptorValueType +{ + Class adaptorClasses[] = { [NSNumber class], + [NSString class], + [NSDate class] }; + EOAdaptorValueType values[] = { EOAdaptorNumberType, + EOAdaptorCharactersType, + EOAdaptorDateType }; + Class class; + int i; + + for ( i = 0; i < 3; i++) + { + class = _valueClass; + + for ( ; class != Nil; class = class_get_super_class(class)) + { + if (class == adaptorClasses[i]) + return values[i]; + } + } + + return EOAdaptorBytesType; +} + +- (EOFactoryMethodArgumentType)factoryMethodArgumentType +{ + return _argumentType; +} + +@end + + +@implementation EOAttribute (EOAttributeValueCreationEditing) + +- (void)setValueFactoryMethodName: (NSString *)factoryMethodName +{ + ASSIGN(_valueFactoryMethodName, factoryMethodName); + _valueFactoryMethod = NSSelectorFromString(_valueFactoryMethodName); +} + +- (void)setAdaptorValueConversionMethodName: (NSString *)conversionMethodName +{ + ASSIGN(_adaptorValueConversionMethodName, conversionMethodName); + + _adaptorValueConversionMethod = NSSelectorFromString(_adaptorValueConversionMethodName); +} + +- (void)setFactoryMethodArgumentType: (EOFactoryMethodArgumentType)argumentType +{ + _argumentType = argumentType; +} + +@end + + +@implementation EOAttribute (EOAttributeValueMapping) + +- (NSException *)validateValue: (id*)valueP +{ + NSException *exception=nil; + + NSAssert(valueP, @"No value pointer"); + + if (*valueP == nil && [self allowsNull] == NO) + exception = [NSException validationExceptionWithFormat: @"attribute '%@' cannot be nil", [self name]]; + else if (*valueP) + { + //call self valueClassName + *valueP = [self adaptorValueByConvertingAttributeValue: *valueP]; + //call attribute width + //end ! + + //TODO: revoir + { + EOEntity *entity = [self entity]; + //NSArray *pkAttributes = [entity primaryKeyAttributes]; + //TODO wowhat + + if (*valueP) + { + if ([*valueP isKindOfClass: _valueClass] == NO) + { + if ([*valueP isKindOfClass: [NSString class]]) + { + if (_valueClass == [NSNumber class]) + { + if ([_valueType isEqualToString: @"i"] == YES) + *valueP = [NSNumber numberWithInt: + [*valueP intValue]]; + else + *valueP = [NSNumber numberWithDouble: + [*valueP doubleValue]]; + } + else if (_valueClass == [NSDecimalNumber class]) + *valueP = [NSDecimalNumber + decimalNumberWithString: *valueP]; + + else if (_valueClass == [NSData class]) + *valueP = [*valueP + dataUsingEncoding: NSASCIIStringEncoding + allowLossyConversion: YES]; + + else if (_valueClass == [NSCalendarDate class]) + *valueP = [[[NSCalendarDate alloc] + initWithString: *valueP] + autorelease]; + } + } + else + { + if ([*valueP isKindOfClass: [NSString class]]) + { + if (_width && [*valueP length] > _width) + { + const char *buf; + + buf = [*valueP cString]; + *valueP = [NSString stringWithCString: buf + length: _width]; + } + } + else if ([*valueP isKindOfClass: [NSNumber class]]) + { + // TODO ?? + } + } + } + } + } + + return exception; +} + +@end + + +@implementation NSObject (EOCustomClassArchiving) + ++ objectWithArchiveData: (NSData *)data +{ + return [NSUnarchiver unarchiveObjectWithData:data]; +} + +- (NSData *)archiveData +{ + return [NSArchiver archivedDataWithRootObject:self]; +} + +@end + + +@implementation EOAttribute (EOAttributePrivate) + +- (void)setParent: (id)parent +{ + //OK + [self willChange]; + ASSIGN(_parent, parent);//TODO assign ?? + + _flags.isParentAnEOEntity = [_parent isKindOfClass: [EOEntity class]];//?? +} + +- (EOAttribute *)realAttribute +{ + return _realAttribute; +} + +- (GCMutableArray *)_definitionArray +{ + return _definitionArray; +} + +@end + +@implementation EOAttribute (EOAttributePrivate2) + +- (BOOL) _hasAnyOverrides +{ + [self notImplemented: _cmd]; //TODO + return NO; +} + +- (void) _resetPrototype +{ + [self notImplemented: _cmd]; //TODO +} + +- (void) _updateFromPrototype +{ + [self notImplemented: _cmd]; //TODO +} + +- (void) _setOverrideForKeyEnum: (int)keyEnum +{ + //[self notImplemented:_cmd]; //TODO +} + +- (BOOL) _isKeyEnumOverriden: (int)param0 +{ + [self notImplemented: _cmd]; //TODO + return NO; +} + +- (BOOL) _isKeyEnumDefinedByPrototype: (int)param0 +{ + [self notImplemented: _cmd]; //TODO + return NO; +} + +@end diff --git a/EOAccess/EOAttributePriv.h b/EOAccess/EOAttributePriv.h new file mode 100644 index 0000000..9bd8751 --- /dev/null +++ b/EOAccess/EOAttributePriv.h @@ -0,0 +1,50 @@ +/* + EOAttributePriv.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: July 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOAttributePriv_h__ +#define __EOAttributePriv_h__ + +@interface EOAttribute (EOAttributePrivate) + +- (GCMutableArray *)_definitionArray; + +- (void)setParent: (id)parent; +- (EOAttribute *)realAttribute; + +@end + +@interface EOAttribute (EOAttributePrivate2) + +- (BOOL) _hasAnyOverrides; +- (void) _resetPrototype; +- (void) _updateFromPrototype; +- (void) _setOverrideForKeyEnum: (int)keyEnum; +- (BOOL) _isKeyEnumOverriden: (int)param0; +- (BOOL) _isKeyEnumDefinedByPrototype: (int)param0; + +@end + +#endif /* __EOAttributePriv_h__ */ diff --git a/EOAccess/EODatabase.h b/EOAccess/EODatabase.h new file mode 100644 index 0000000..f7beb44 --- /dev/null +++ b/EOAccess/EODatabase.h @@ -0,0 +1,113 @@ +/* + EODatabase.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: Jun 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EODatabase_h__ +#define __EODatabase_h__ + +#import + +@class EOAdaptor; +@class EOModel; +@class EOEntity; + +@class EODatabaseContext; +@class EOGlobalID; +@class EOEditingContext; + + +extern NSString *EOGeneralDatabaseException; + + +@interface EODatabase : NSObject +{ + NSMutableArray *_registeredContexts; + NSMutableDictionary *_snapshots; + NSMutableArray *_models; + NSMutableDictionary *_entityCache; + EOAdaptor *_adaptor; + NSMutableDictionary *_toManySnapshots; +} + ++ (EODatabase *)databaseWithModel: (EOModel *)model; + +- initWithAdaptor: (EOAdaptor *)adaptor; + +- initWithModel: (EOModel *)model; + +- (NSArray *)registeredContexts; + +- (void)registerContext: (EODatabaseContext *)context; +- (void)unregisterContext: (EODatabaseContext *)context; + +- (EOAdaptor *)adaptor; + +- (void)addModel: (EOModel *)model; +- (void)removeModel: (EOModel *)model; +- (BOOL)addModelIfCompatible: (EOModel *)model; + +- (NSArray *)models; + +- (EOEntity *)entityNamed: (NSString *)entityName; + +- (EOEntity *)entityForObject: (id)object; + +- (NSArray *)resultCacheForEntityNamed: (NSString *)name; +- (void)setResultCache: (NSArray *)cache forEntityNamed: (NSString *)name; +- (void)invalidateResultCacheForEntityNamed: (NSString *)name; +- (void)invalidateResultCache; +- (void)handleDroppedConnection; +@end + + +@interface EODatabase (EOUniquing) + +- (void)recordSnapshot: (NSDictionary *)snapshot forGlobalID: (EOGlobalID *)gid; + +- (NSDictionary *)snapshotForGlobalID:(EOGlobalID *)gid; + +- (void)recordSnapshot:(NSArray *)gids + forSourceGlobalID:(EOGlobalID *)gid + relationshipName:(NSString *)name; + +- (NSArray *)snapshotForSourceGlobalID: (EOGlobalID *)gid + relationshipName: (NSString *)name; + +- (void)forgetSnapshotForGlobalID: (EOGlobalID *)gid; + +- (void)forgetSnapshotsForGlobalIDs: (NSArray *)array; + +- (void)forgetAllSnapshots; + +- (void)recordSnapshots: (NSDictionary *)snapshots; + +- (void)recordToManySnapshots: (NSDictionary *)snapshots; + +- (NSDictionary *)snapshots; + +@end + + +#endif /* __EODatabase_h__ */ diff --git a/EOAccess/EODatabase.m b/EOAccess/EODatabase.m new file mode 100644 index 0000000..127f117 --- /dev/null +++ b/EOAccess/EODatabase.m @@ -0,0 +1,617 @@ +/** + EODatabase.m EODatabase Class + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: June 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import + +#import +#import +#import +#import +#import +#import + +#import +#import + +#import +#import +#import +#import +#import + +#import +#import + +#import + +/* TODO + + Controllare il resultCache, ad ogni forget/invalidate deve essere + updatato. + */ + +NSString *EOGeneralDatabaseException = @"EOGeneralDatabaseException"; + + +@implementation EODatabase + +/* + * Database Global Methods + */ + +static NSMutableArray *databaseInstances; + ++ (void)initialize +{ + // THREAD + databaseInstances = [NSMutableArray new]; +} + ++ (void)makeAllDatabasesPerform: (SEL)aSelector withObject: anObject +{ + int i; + + // THREAD + for (i = [databaseInstances count] - 1; i >= 0; i--) + [[[databaseInstances objectAtIndex: i] nonretainedObjectValue] + performSelector: aSelector withObject: anObject]; +} + +/* + * Initializing new instances + */ +//OK +- initWithAdaptor: (EOAdaptor *)adaptor +{ + EOFLOGObjectFnStart(); + + if (!adaptor) + { + [self autorelease]; + return nil; + } + + if ((self = [super init])) + { + [[NSNotificationCenter defaultCenter] + addObserver: self + selector: @selector(_globalIDChanged:) + name: @"EOGlobalIDChangedNotification" + object: nil]; + // [databaseInstances addObject:[NSValue valueWithNonretainedObject:self]]; + ASSIGN(_adaptor,adaptor); + + _registeredContexts = [NSMutableArray new]; + _snapshots = [NSMutableDictionary new]; + _models = [NSMutableArray new]; + _entityCache = [NSMutableDictionary new]; + _toManySnapshots = [NSMutableDictionary new]; + } + + EOFLOGObjectFnStop(); + + return self; +} + ++ (EODatabase *)databaseWithModel: (EOModel *)model +{ + return [[[self alloc] initWithModel: model] autorelease]; +} + +- (id)initWithModel: (EOModel *)model +{ + EOAdaptor *adaptor = [EOAdaptor adaptorWithModel:model]; //Handle exception to deallocate self ? + + if ((self = [self initWithAdaptor: adaptor])) + { + [self addModel: model]; + } + + return self; +} + +- (void)dealloc +{ + [_adaptor release]; + [_registeredContexts release]; + [_snapshots release]; + [_models release]; + [_entityCache release]; + [_toManySnapshots release]; + + [super dealloc]; +} + +- (NSArray *)registeredContexts +{ + NSMutableArray *array = [NSMutableArray array]; + int i, n; + + for (i = 0, n = [_registeredContexts count]; i < n; i++) + [array addObject: [[_registeredContexts objectAtIndex: i] + nonretainedObjectValue]]; + + return array; +} + +- (unsigned int) _indexOfRegisteredContext: (EODatabaseContext *)context +{ + int i; + + for( i = [_registeredContexts count]-1; i >= 0; i--) + if ([[_registeredContexts objectAtIndex: i] + nonretainedObjectValue] == context) + { + return i; + } + + return -1; +} + +- (void)registerContext: (EODatabaseContext *)context +{ + unsigned int index=0; + + //OK + + NSAssert(([context database] == self),@"Database context is not me"); + + index = [self _indexOfRegisteredContext:context]; + + NSAssert(index == (unsigned int) -1 , @"DatabaseContext already registred"); + + [_registeredContexts addObject: + [NSValue valueWithNonretainedObject: context]]; +} + +- (void)unregisterContext: (EODatabaseContext *)context +{ + //OK + unsigned int index = [self _indexOfRegisteredContext:context]; + + NSAssert(index != (unsigned int) -1, @"DatabaseContext wasn't registred"); + + [_registeredContexts removeObjectAtIndex:index]; +} + +- (EOAdaptor *)adaptor +{ + return _adaptor; +} + +- (void)addModel: (EOModel *)model +{ + [_models addObject: model]; +} + +- (void)removeModel: (EOModel *)model +{ + [_models removeObject: model]; +} + +- (BOOL)addModelIfCompatible: (EOModel *)model; +{ + BOOL modelOk = NO; + + NSAssert(model, @"No model");//WO simply return NO (doesn't handle this case). + + if ([_models containsObject:model] == YES) + modelOk = YES; + else + { + EOAdaptor *adaptor = [self adaptor]; + + if ([[model adaptorName] isEqualToString: [adaptor name]] == YES + || [_adaptor canServiceModel: model] == YES) + { + [_models addObject: model]; + modelOk = YES; + } + } + + return modelOk; +} + +- (NSArray *)models +{ + return _models; +} + +- (EOEntity *)entityNamed: (NSString *)entityName +{ + //OK + EOEntity *entity=nil; + int i = 0; + int count = 0; + + NSAssert(entityName, @"No entity name"); + + count = [_models count]; + + for(i = 0; !entity && i < count; i++) + { + EOModel *model = [_models objectAtIndex: i]; + + entity = [model entityNamed: entityName]; + } + + return entity; +} + +- (EOEntity *)entityForObject: (id)object +{ + //OK + EOEntity *entity = nil; + NSString *entityName = nil; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"object=%p (of class %@)", + object, [object class]); + NSAssert(object, @"No object"); + + if ([EOFault isFault: object]) + { + EOFaultHandler *faultHandler = [EOFault handlerForFault: object]; + EOKeyGlobalID *gid; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"faultHandler=%p (of class %@)", + faultHandler, [faultHandler class]); + + gid = [(EOAccessFaultHandler *)faultHandler globalID]; + + NSAssert3(gid, @"No gid for fault handler %p for object %p of class %@", + faultHandler, object, [object class]); + entityName = [gid entityName]; + } + else + entityName = [object entityName]; + + NSAssert2(entityName, @"No object entity name for object %@ of class %@", + object, [object class]); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"entityName=%@", entityName); + + entity = [self entityNamed: entityName]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"entity=%p", entity); + EOFLOGObjectFnStop(); + + return entity; +} + +- (NSArray *)resultCacheForEntityNamed: (NSString *)name +{ + return [_entityCache objectForKey: name]; +} + +- (void)setResultCache: (NSArray *)cache + forEntityNamed: (NSString *)name +{ + EOFLOGObjectFnStart(); + + [_entityCache setObject: cache + forKey: name]; + + EOFLOGObjectFnStop(); +} + +- (void)invalidateResultCacheForEntityNamed: (NSString *)name +{ + [_entityCache removeObjectForKey: name];//?? +} + +- (void)invalidateResultCache +{ + [_entityCache removeAllObjects]; +} + +- (void)handleDroppedConnection +{ + NSArray *dbContextArray; + NSEnumerator *contextEnum; + EODatabaseContext *dbContext; + + EOFLOGObjectFnStartOrCond2(@"DatabaseLevel", @"EODatabase"); + + [_adaptor handleDroppedConnection]; + + dbContextArray = [self registeredContexts]; + contextEnum = [dbContextArray objectEnumerator]; + + while ((dbContext = [contextEnum nextObject])) + [dbContext handleDroppedConnection]; + + EOFLOGObjectFnStopOrCond2(@"DatabaseLevel", @"EODatabase"); +} + +@end + + +@implementation EODatabase (EOUniquing) + +- (void)recordSnapshot: (NSDictionary *)snapshot + forGlobalID: (EOGlobalID *)gid +{ + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"snapshot %p %@", snapshot, snapshot); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"gid=%@", gid); + + NSAssert(gid, @"No gid"); + NSAssert(snapshot, @"No snapshot"); + NSAssert(_snapshots, @"No _snapshots"); + + [_snapshots setObject: snapshot + forKey: gid]; + + NSAssert([_snapshots objectForKey: gid], @"SNAPSHOT not save !!"); + + EOFLOGObjectFnStop(); +} + +//"Receive EOGlobalIDChangedNotification notification" +- (void)_globalIDChanged: (NSNotification *)notification +{ + NSDictionary *snapshot = nil; + NSDictionary *userInfo = nil; + NSEnumerator *enumerator = nil; + EOGlobalID *tempGID = nil; + EOGlobalID *gid = nil; + + EOFLOGObjectFnStart(); + + userInfo = [notification userInfo]; + enumerator = [userInfo keyEnumerator]; + + while ((tempGID = [enumerator nextObject])) + { + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"tempGID=%@", tempGID); + + gid = [userInfo objectForKey: tempGID]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"gid=%@", gid); + + //OK ? + snapshot = [_snapshots objectForKey: tempGID]; + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"_snapshots snapshot=%@", snapshot); + + if (snapshot) + { + [_snapshots removeObjectForKey: tempGID]; + [_snapshots setObject: snapshot + forKey: gid]; + } + + //OK ? + snapshot = [_toManySnapshots objectForKey: tempGID]; + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"_toManySnapshots snapshot=%@", + snapshot); + + if (snapshot) + { + [_toManySnapshots removeObjectForKey: tempGID]; + [_toManySnapshots setObject: snapshot + forKey: gid]; + } + } + + EOFLOGObjectFnStop(); +} + +- (NSDictionary *)snapshotForGlobalID: (EOGlobalID *)gid +{ + //seems OK + NSDictionary *snapshot = nil; + + EOFLOGObjectFnStart(); + + NSAssert(gid, @"No gid"); + + snapshot = [_snapshots objectForKey: gid]; + + EOFLOGObjectFnStop(); + + return snapshot; +} + +- (void)recordSnapshot: (NSArray*)gids + forSourceGlobalID: (EOGlobalID *)gid + relationshipName: (NSString *)name +{ + //OK + NSMutableDictionary *toMany = nil; + + EOFLOGObjectFnStart(); + + NSAssert(gid,@"No snapshot"); + NSAssert(gid,@"No Source Global ID"); + NSAssert(name,@"No relationship name"); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"self=%p snapshot gids=%@", self, gids); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"SourceGlobalID gid=%@", gid); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"relationshipName=%@", name); + + toMany = [_toManySnapshots objectForKey: gid]; + + if (!toMany) + { + toMany = [NSMutableDictionary dictionaryWithCapacity: 10]; + [_toManySnapshots setObject: toMany + forKey: gid]; + } + + [toMany setObject: gids + forKey: name]; + + EOFLOGObjectFnStop(); +} + +- (NSArray *)snapshotForSourceGlobalID: (EOGlobalID *)gid + relationshipName: (NSString *)name +{ + NSAssert(gid, @"No Source Global ID"); + NSAssert(name, @"No relationship name"); + + return [[_toManySnapshots objectForKey: gid] objectForKey: name]; +} + +- (void)forgetSnapshotForGlobalID: (EOGlobalID *)gid +{ + //Seems OK + EOFLOGObjectFnStart(); + + NSAssert(gid,@"No Global ID"); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"gid=%@", gid); + + [_snapshots removeObjectForKey: gid]; + [_toManySnapshots removeObjectForKey: gid]; + + [[NSNotificationCenter defaultCenter] + postNotificationName: EOObjectsChangedInStoreNotification + object: self + userInfo: [NSDictionary dictionaryWithObject: + [NSArray arrayWithObject: gid] + forKey: EOInvalidatedKey]]; + + EOFLOGObjectFnStop(); +}; + +- (void)forgetSnapshotsForGlobalIDs: (NSArray*)ids +{ + NSEnumerator *gidEnum = nil; + id gid = nil; + + EOFLOGObjectFnStart(); + + NSAssert(ids, @"No Global IDs"); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"ids=%@", ids); + + gidEnum = [ids objectEnumerator]; + + while ((gid = [gidEnum nextObject])) + { + [_snapshots removeObjectForKey: gid]; + [_toManySnapshots removeObjectForKey: gid]; + } + + [[NSNotificationCenter defaultCenter] + postNotificationName: EOObjectsChangedInStoreNotification + object: self + userInfo: [NSDictionary dictionaryWithObject: ids + forKey: EOInvalidatedKey]]; + + EOFLOGObjectFnStop(); +} + +- (void)forgetAllSnapshots +{ + NSMutableSet *gidSet = [NSMutableSet new]; + NSMutableArray *gidArray = [NSMutableArray array]; + + EOFLOGObjectFnStartOrCond2(@"DatabaseLevel", @"EODatabase"); + + [gidSet addObjectsFromArray: [_snapshots allKeys]]; + [gidSet addObjectsFromArray: [_toManySnapshots allKeys]]; + [gidArray addObjectsFromArray: [gidSet allObjects]]; + [gidSet release]; + [_snapshots removeAllObjects]; + [_toManySnapshots removeAllObjects]; + + [[NSNotificationCenter defaultCenter] + postNotificationName: EOObjectsChangedInStoreNotification + object:self + userInfo: [NSDictionary dictionaryWithObject: gidArray + forKey: EOInvalidatedKey]]; + + EOFLOGObjectFnStopOrCond2(@"DatabaseLevel", @"EODatabase"); +} + +- (void)recordSnapshots: (NSDictionary *)snapshots +{ + //OK + //VERIFY: be sure to replace all anapshot entries if any ! + EOFLOGObjectFnStart(); + + [_snapshots addEntriesFromDictionary: snapshots]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"self=%p _snapshots=%@", + self, _snapshots); + + EOFLOGObjectFnStop(); +} + +- (void)recordToManySnapshots: (NSDictionary *)snapshots +{ +//Seems OK + NSEnumerator *keyEnum = nil; + id key = nil; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"snapshots=%@", snapshots); + NSAssert(snapshots, @"No snapshots"); + + keyEnum = [snapshots keyEnumerator]; + + while ((key = [keyEnum nextObject])) + { + NSMutableDictionary *toMany = nil; + + toMany = [_toManySnapshots objectForKey: key]; // look if already exists + + if (!toMany) + { + toMany = [NSMutableDictionary dictionaryWithCapacity: 10]; + [_toManySnapshots setObject: toMany + forKey: key]; + } + + [toMany addEntriesFromDictionary: [snapshots objectForKey: key]]; + } + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"snapshots=%@", snapshots); + + EOFLOGObjectFnStop(); +} + +- (NSDictionary *)snapshots +{ + return _snapshots; +} + +@end /* EODatabase (EOUniquing) */ + diff --git a/EOAccess/EODatabaseChannel.h b/EOAccess/EODatabaseChannel.h new file mode 100644 index 0000000..e4ab301 --- /dev/null +++ b/EOAccess/EODatabaseChannel.h @@ -0,0 +1,92 @@ +/* + EODatabaseChannel.h + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: July 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EODatabaseChannel_h__ +#define __EODatabaseChannel_h__ + +#import +#import + +@class EOAdaptorChannel; +@class EORelationship; +@class EODatabaseContext; + + +@interface EODatabaseChannel : NSObject +{ + EODatabaseContext *_databaseContext; + id _delegate; + EOAdaptorChannel *_adaptorChannel; + EOEntity *_currentEntity; + EOEditingContext *_currentEditingContext; + NSMutableArray *_fetchProperties; + NSMutableArray *_fetchSpecifications; + BOOL _isLocking; + BOOL _isRefreshingObjects; + + struct { + unsigned int shouldSelectObjects:1; + unsigned int didSelectObjects:1; + unsigned int shouldUsePessimisticLock:1; + unsigned int shouldUpdateSnapshot:1; + unsigned int _reserved:28; + } _delegateRespondsTo; +} + ++ (EODatabaseChannel*)databaseChannelWithDatabaseContext: (EODatabaseContext *)databaseContext; + +- initWithDatabaseContext: (EODatabaseContext *)databaseContext; + +- (void)setCurrentEntity: (EOEntity *)entity; +- (void) setEntity: (EOEntity *)entity; + +- (void)setCurrentEditingContext: (EOEditingContext *)context; + +- (void)selectObjectsWithFetchSpecification: (EOFetchSpecification *)fetchSpecification + editingContext: (EOEditingContext *)context; + +- (id)fetchObject; + +- (BOOL)isFetchInProgress; + +- (void)cancelFetch; + +- (EODatabaseContext *)databaseContext; + +- (EOAdaptorChannel *)adaptorChannel; + +- (BOOL)isRefreshingObjects; +- (void)setIsRefreshingObjects: (BOOL)yn; + +- (BOOL)isLocking; +- (void)setIsLocking: (BOOL)isLocking; + +- (void)setDelegate: (id)delegate; +- (id) delegate; + +@end + +#endif /* __EODatabaseChannel_h__ */ diff --git a/EOAccess/EODatabaseChannel.m b/EOAccess/EODatabaseChannel.m new file mode 100644 index 0000000..2c5b933 --- /dev/null +++ b/EOAccess/EODatabaseChannel.m @@ -0,0 +1,792 @@ +/** + EODatabaseChannel.m EODatabaseChannel + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: June 2000 + + Author: Manuel Guesdon + Date: October 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import + +#import +#import +#import +#import +#import +#import + +#import +#import +#import +#import +#import +#import +#import + +#import +#import +#import +#import +#import +#import + +@implementation EODatabaseChannel + ++ (void)load +{ + [[NSNotificationCenter defaultCenter] + addObserver: self + selector: @selector(_registerDatabaseChannel:) + name: EODatabaseChannelNeededNotification + object: nil]; +} + ++ (void)_registerDatabaseChannel: (NSNotification *)notification +{ + // TODO who release it ? + [[EODatabaseChannel alloc] initWithDatabaseContext: [notification object]]; +} + ++ (EODatabaseChannel*)databaseChannelWithDatabaseContext: (EODatabaseContext *)databaseContext +{ + return [[[self alloc] initWithDatabaseContext: databaseContext] autorelease]; +} + +- (id) initWithDatabaseContext:(EODatabaseContext *)databaseContext +{ + if ((self = [super init])) + { + ASSIGN(_databaseContext, databaseContext); + ASSIGN(_adaptorChannel, [[_databaseContext adaptorContext] + createAdaptorChannel]); +//TODO NO<<<< + [_adaptorChannel openChannel]; + + _fetchProperties = [NSMutableArray new]; + _fetchSpecifications = [NSMutableArray new]; +//NO>>>>>>> + [_databaseContext registerChannel: self];//should be in caller + } + + return self; +} + +- (void)dealloc +{ + [_databaseContext unregisterChannel: self]; + + DESTROY(_databaseContext); + [_adaptorChannel closeChannel]; + + DESTROY(_adaptorChannel); + DESTROY(_currentEntity); + DESTROY(_currentEditingContext); + DESTROY(_fetchProperties); + DESTROY(_fetchSpecifications); + + [super dealloc]; +} + +- (void)setCurrentEntity: (EOEntity *)entity +{ + //OK + ASSIGN(_currentEntity, entity); + [self setEntity: entity]; +} + +- (void) setEntity: (EOEntity *)entity +{ + //Near OK + NSArray *relationships = [entity relationships]; + int i = 0; + int count = [relationships count]; + + NSDebugMLLog(@"gsdb", @"relationships=%@", relationships); + + for (i = 0; i < count; i++) + { + EORelationship *relationship = [relationships objectAtIndex:i]; + EOEntity *destinationEntity = [relationship destinationEntity]; + EOModel *destinationEntityModel = [destinationEntity model]; + EOEntity *entity = [relationship entity]; + EOModel *entityModel = [entity model]; + + NSDebugMLLog(@"gsdb", @"relationship=%@", relationship); + NSDebugMLLog(@"gsdb", @"destinationEntity=%@", [destinationEntity name]); + + NSAssert2(destinationEntity, @"No destinationEntity in relationship: %@ of entity %@", + relationship, [entity name]); //TODO: flattened relationship + + NSDebugMLLog(@"gsdb", @"entity=%@", [entity name]); + NSDebugMLLog(@"gsdb", @"destinationEntityModel=%p", destinationEntityModel); + NSDebugMLLog(@"gsdb", @"entityModel=%p", entityModel); + + //If different: try to add destinationEntityModel + if (destinationEntityModel != entityModel) + { + EOEditingContext *editingContext = [self currentEditingContext]; + //EODatabaseContext *databaseContext = [self databaseContext]; + EOObjectStore *rootObjectStore = [editingContext rootObjectStore]; + NSArray *cooperatingObjectStores = + [(EOObjectStoreCoordinator *)rootObjectStore + cooperatingObjectStores]; + int cosCount = [cooperatingObjectStores count]; + int i; + + for (i = 0; i < cosCount; i++) + { + id objectStore = [cooperatingObjectStores objectAtIndex: i]; + EODatabase *objectStoreDatabase = [objectStore database]; + BOOL modelOK = [objectStoreDatabase + addModelIfCompatible: destinationEntityModel]; + + if (!modelOK) + { + /*EODatabase *dbDatabase = [[[EODatabase alloc] + initWithModel: destinationEntityModel] autorelease];*/ + [self notImplemented: _cmd]; //TODO: finish it + } + } + } + } +} + +- (void)setCurrentEditingContext: (EOEditingContext*)context +{ + //OK + EOCooperatingObjectStore *cooperatingObjectStore = [self databaseContext]; + EOObjectStore *objectStore = [context rootObjectStore]; + + [(EOObjectStoreCoordinator*)objectStore + addCooperatingObjectStore: cooperatingObjectStore]; + + ASSIGN(_currentEditingContext, context); +} + +- (void)selectObjectsWithFetchSpecification: (EOFetchSpecification *)fetch + editingContext: (EOEditingContext *)context +{ + //should be OK + NSString *entityName = nil; + EODatabase *database = nil; + EOEntity *entity = nil; + EOQualifier *qualifier = nil; + EOQualifier *schemaBasedQualifier = nil; + + EOFLOGObjectFnStart(); + + entityName = [fetch entityName]; + database = [_databaseContext database]; + + NSDebugMLLog(@"gsdb", @"database=%@", database); + + entity = [database entityNamed: entityName]; + + NSDebugMLLog(@"gsdb", @"entity name=%@", [entity name]); + + qualifier=[fetch qualifier]; + + NSDebugMLLog(@"gsdb", @"qualifier=%@", qualifier); + + schemaBasedQualifier = + [(id)qualifier + schemaBasedQualifierWithRootEntity: entity]; + + NSDebugMLLog(@"gsdb", @"schemaBasedQualifier=%@", schemaBasedQualifier); + NSDebugMLLog(@"gsdb", @"qualifier=%@", qualifier); + + if (schemaBasedQualifier && schemaBasedQualifier != qualifier) + { + EOFetchSpecification *newFetch = nil; + + NSDebugMLLog(@"gsdb", @"fetch=%@", fetch); + //howto avoid copy of uncopiable qualifiers (i.e. those who contains uncopiable key or value) + + NSDebugMLLog(@"gsdb", @"fetch=%@", fetch); + + newFetch = [[fetch copy] autorelease]; + NSDebugMLLog(@"gsdb", @"newFetch=%@", newFetch); + + [newFetch setQualifier: schemaBasedQualifier]; + NSDebugMLLog(@"gsdb", @"newFetch=%@", newFetch); + + fetch = newFetch; + } + + NSDebugMLLog(@"gsdb", @"%@ -- %@ 0x%x: isFetchInProgress=%s", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + ([self isFetchInProgress] ? "YES" : "NO")); + + [self _selectWithFetchSpecification:fetch + editingContext:context]; + + EOFLOGObjectFnStop(); +} + +- (id)fetchObject +{ + //seems OK + EODatabase *database=nil; + id object = nil; + + EOFLOGObjectFnStart(); + + database = [_databaseContext database]; + + if (![self isFetchInProgress]) + { + NSLog(@"No Fetch in progress"); + NSDebugMLog(@"No Fetch in progress"); + + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: no fetch in progress", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + } + else + { + NSArray *propertiesToFetch=nil; + NSDictionary *row =nil; + + NSAssert(_currentEditingContext, @"No current editing context"); + NSAssert(_adaptorChannel,@"No adaptor channel"); + + propertiesToFetch = [self _propertiesToFetch]; + + NSDebugMLLog(@"gsdb", @"Will fetchRow"); + + row = [_adaptorChannel fetchRowWithZone: NULL]; + + NSDebugMLLog(@"gsdb", @"row=%@", row); + //NSDebugMLog(@"TEST attributesToFetch=%@", [_currentEntity attributesToFetch]); + + if (!row) + { + //TODO + //VERIFY + /* + if no more obj: + if transactionNestingLevel + adaptorContext transactionDidCommit + */ + } + else + { + BOOL isObjectNew = YES; //TODO used to avoid double fetch. We should see how to do when isRefreshingObjects == YES + EOGlobalID *gid; + NSDictionary *snapshot = nil; + + NSAssert(_currentEntity, @"Not current Entity"); + + gid = [_currentEntity globalIDForRow: row + isFinal: YES];//OK + + NSDebugMLLog(@"gsdb",@"gid=%@",gid); + //NSDebugMLog(@"TEST attributesToFetch=%@",[_currentEntity attributesToFetch]); + + object = [_currentEditingContext objectForGlobalID: gid]; //OK //nil + + NSDebugMLLog(@"gsdb",@"object=%@",object); + + if (object) + isObjectNew = NO; + + NSAssert(_databaseContext,@"No database context"); + + snapshot = [_databaseContext snapshotForGlobalID: gid]; //OK + + NSDebugMLLog(@"gsdb", @"snapshot=%@", snapshot); + //NSDebugMLog(@"TEST attributesToFetch=%@", [_currentEntity attributesToFetch]); + + if (snapshot) + { + NSDebugMLLog(@"gsdb", @"_delegateRespondsTo.shouldUpdateSnapshot=%d", + (int)_delegateRespondsTo.shouldUpdateSnapshot); + NSDebugMLLog(@"gsdb", @"[self isLocking]=%d", + (int)[self isLocking]); + NSDebugMLLog(@"gsdb", @"[self isRefreshingObjects]=%d", + (int)[self isRefreshingObjects]); + + //mirko: + if((_delegateRespondsTo.shouldUpdateSnapshot == NO + && ([self isLocking] == YES + || [self isRefreshingObjects] == YES)) + || (_delegateRespondsTo.shouldUpdateSnapshot == YES + && (row = (id)[_delegate databaseContext: _databaseContext + shouldUpdateCurrentSnapshot: snapshot + newSnapshot: row + globalID: gid + databaseChannel: self]))) + { // TODO delegate not correct ! + NSDebugMLLog(@"gsdb", @"Updating Snapshot=%@", snapshot); + NSDebugMLLog(@"gsdb", @"row=%@", row); + + [_databaseContext recordSnapshot: row + forGlobalID: gid]; + isObjectNew = YES; //TODO + } + } + else + { + //NSDebugMLog(@"TEST attributesToFetch=%@", [_currentEntity attributesToFetch]); + NSDebugMLLog(@"gsdb", @"database class=%@", [database class]); + + NSAssert(database, @"No database-context database"); + + [database recordSnapshot: row + forGlobalID: gid]; + } + + NSDebugMLLog(@"gsdb", @"[self isRefreshingObjects]=%d", + (int)[self isRefreshingObjects]); + + //From mirko + if ([self isRefreshingObjects] == YES) + { + [[NSNotificationCenter defaultCenter] + postNotificationName: EOObjectsChangedInStoreNotification + object: _databaseContext + userInfo: [NSDictionary dictionaryWithObject: + [NSArray arrayWithObject:gid] + forKey: EOUpdatedKey]]; //OK ? + } + + if (!object) + { + EOClassDescription *entityClassDescripton = [_currentEntity classDescriptionForInstances]; + + object = [entityClassDescripton createInstanceWithEditingContext: _currentEditingContext + globalID: gid + zone: NULL]; + + //NSDebugMLog(@"TEST attributesToFetch=%@", [_currentEntity attributesToFetch]); + NSDebugMLLog(@"gsdb", @"object=%@", object); + NSAssert1(object, @"No Object. entityClassDescripton=%@", entityClassDescripton); + + [_currentEditingContext recordObject: object + globalID: gid]; + } + else if (object && [EOFault isFault: object]) + { + EOAccessFaultHandler *handler = [EOFault handlerForFault: object]; + EOKeyGlobalID *handlerGID = (EOKeyGlobalID *)[handler globalID]; + + isObjectNew = YES; //TODO + + [handlerGID isFinal]; //YES //TODO + [EOFault clearFault: object]; + + /*mirko: + [_databaseContext _removeBatchForGlobalID:gid + fault:obj]; + + [EOFault clearFault:obj]; + */ + } + + if (isObjectNew) //TODO + { + [EOObserverCenter suppressObserverNotification]; + + NS_DURING + { + NSDebugMLLog(@"gsdb", @"Initialize %p", object); + + [_currentEditingContext initializeObject: object + withGlobalID: gid + editingContext: _currentEditingContext]; + } + NS_HANDLER + { + [EOObserverCenter enableObserverNotification]; + [localException raise]; + } + NS_ENDHANDLER; + + [EOObserverCenter enableObserverNotification]; + [object awakeFromFetchInEditingContext: _currentEditingContext]; + } + } + } + + EOFLOGObjectFnStop(); + + return object; +}; + +- (BOOL)isFetchInProgress +{ + //NSDebugMLog(@"TEST attributesToFetch=%@", [_currentEntity attributesToFetch]); + + return [_adaptorChannel isFetchInProgress]; +} + +- (void)cancelFetch +{ + EOFLOGObjectFnStart(); + + [self _cancelInternalFetch]; + + //TODO VERIFY - NO ??!! + [_adaptorChannel cancelFetch]; + [_fetchProperties removeAllObjects]; + [_fetchSpecifications removeAllObjects]; + + EOFLOGObjectFnStop(); +} + +- (EODatabaseContext *)databaseContext +{ + return _databaseContext; +} + +- (EOAdaptorChannel *)adaptorChannel +{ + return _adaptorChannel; +} + +- (BOOL)isRefreshingObjects +{ + return _isRefreshingObjects; +} + +- (void)setIsRefreshingObjects: (BOOL)yn +{ + _isRefreshingObjects = yn; +} + +- (BOOL)isLocking +{ + return _isLocking; +} + +- (void)setIsLocking: (BOOL)isLocking +{ + _isLocking = isLocking; +} + +- (void)setDelegate: delegate +{ + _delegate = delegate; + + _delegateRespondsTo.shouldSelectObjects = + [delegate respondsToSelector:@selector(databaseContext:shouldSelectObjectsWithFetchSpecification:databaseChannel:)]; + _delegateRespondsTo.didSelectObjects = + [delegate respondsToSelector:@selector(databaseContext:didSelectObjectsWithFetchSpecification:databaseChannel:)]; + _delegateRespondsTo.shouldUsePessimisticLock = + [delegate respondsToSelector:@selector(databaseContext:shouldUsePessimisticLockWithFetchSpecification: databaseChannel:)]; + _delegateRespondsTo.shouldUpdateSnapshot = + [delegate respondsToSelector:@selector(databaseContext:shouldUpdateCurrentSnapshot:newSnapshot:globalID:databaseChannel:)]; +} + +- delegate +{ + return _delegate; +} + + +@end + +@implementation EODatabaseChannel (EODatabaseChannelPrivate) +- (NSArray*) _propertiesToFetch +{ + //OK + NSArray *attributesToFetch=nil; + + EOFLOGObjectFnStart(); + + attributesToFetch = [_currentEntity _attributesToFetch]; + + NSAssert(_currentEntity, @"No current Entity"); + + EOFLOGObjectFnStop(); + + return attributesToFetch; +} + +-(void)_setCurrentEntityAndRelationshipWithFetchSpecification: (EOFetchSpecification *)fetch +{ + //OK + NSString *entityName = [fetch entityName]; + EODatabase *database = [_databaseContext database]; + EOEntity *entity = [database entityNamed: entityName]; + + NSAssert1(entity, @"No Entity named %@", entityName); + + [self setCurrentEntity: entity]; +} + +- (void) _buildNodeList:(id) param0 + withParent:(id) param1 +{ + //TODO + [self notImplemented: _cmd]; +} + +- (id) currentEditingContext +{ + return _currentEditingContext; +} + +- (void) _cancelInternalFetch +{ + //OK + EOFLOGObjectFnStart(); + + if ([_adaptorChannel isFetchInProgress]) + { + [_adaptorChannel cancelFetch]; + } + + EOFLOGObjectFnStop(); +} + +- (void) _closeChannel +{ + //TODO + [self notImplemented: _cmd]; +} + +- (void) _openChannel +{ + //TODO + [self notImplemented: _cmd]; +} + +- (void)_selectWithFetchSpecification: (EOFetchSpecification *)fetch + editingContext: (EOEditingContext *)context +{ + NSArray *propertiesToFetch = nil; + EOUpdateStrategy updateStrategy = EOUpdateWithOptimisticLocking; + BOOL fetchLocksObjects = NO; + BOOL refreshesRefetchedObjects = NO; + NSString *entityName = nil; + EODatabase *database = nil; + EOEntity *entity = nil; + NSArray *primaryKeyAttributes = nil; + NSDictionary *hints = nil; + EOModel *model = nil; + EOModelGroup *modelGroup = nil; + EOQualifier *qualifier = nil; + EOStoredProcedure *storedProcedure = nil; + id customQueryExpressionHint = nil;//TODO + EOSQLExpression *customQueryExpression = nil;//TODO + NSString *storedProcedureName = nil; + + BOOL isDeep = NO; + NSArray *subEntities = nil; + NSDictionary *_hints = nil; + + EOFLOGObjectFnStart(); + + _hints = [fetch _hints]; + + customQueryExpressionHint = [_hints objectForKey: @"EOCustomQueryExpressionHintKey"];//TODO use it + + if (customQueryExpressionHint) + { + EOAdaptorContext *adaptorContext = nil; + EOAdaptor *adaptor = nil; + Class expressionClass = Nil; + + NSDebugMLLog(@"gsdb", @"customQueryExpressionHint=%@", customQueryExpressionHint); + + adaptorContext = [_databaseContext adaptorContext]; + + NSDebugMLLog(@"gsdb", @"adaptorContext=%p", adaptorContext); + + adaptor = [adaptorContext adaptor]; + + NSDebugMLLog(@"gsdb", @"adaptor=%p", adaptor); + NSDebugMLLog(@"gsdb", @"adaptor=%@", adaptor); + NSDebugMLLog(@"gsdb", @"adaptor class=%@", [adaptor class]); + + //TODO VERIFY + expressionClass = [adaptor expressionClass]; + NSDebugMLLog(@"gsdb", @"expressionClass=%@", expressionClass); + + customQueryExpression = [expressionClass expressionForString: + customQueryExpressionHint]; + + NSDebugMLLog(@"gsdb", @"customQueryExpression=%@", customQueryExpression); + } + + [self setCurrentEditingContext: context]; //OK even if customQueryExpressionHintKey + [self _setCurrentEntityAndRelationshipWithFetchSpecification: fetch]; + + isDeep = [fetch isDeep]; //ret 1 + + if (!customQueryExpressionHint) + { + subEntities = [entity subEntities]; + NSDebugMLLog(@"gsdb", @"subEntities=%@", subEntities); + + //Strange + { + NSMutableArray *array = nil; + + array = [NSMutableArray arrayWithCapacity: 8]; + + if ([subEntities count] > 0 && isDeep) + { + //?? + NSEnumerator *subEntitiesEnum = [subEntities objectEnumerator]; + id subEntity = nil; + + while ((subEntity = [subEntitiesEnum nextObject])) + { + EOFetchSpecification *fetchSubEntity; + + fetchSubEntity = [[fetch copy] autorelease]; + [fetchSubEntity setEntityName: [entity name]]; + + [array addObjectsFromArray: + [context objectsWithFetchSpecification: + fetchSubEntity]]; + } + } + } + } + + propertiesToFetch = [self _propertiesToFetch]; + updateStrategy = [_databaseContext updateStrategy];//Ret 0 + fetchLocksObjects = [fetch locksObjects]; + refreshesRefetchedObjects = [fetch refreshesRefetchedObjects]; + entityName = [fetch entityName]; + database = [_databaseContext database]; + entity = [database entityNamed:entityName]; + primaryKeyAttributes = [entity primaryKeyAttributes]; + hints = [fetch hints]; // ret {} + storedProcedureName = [hints objectForKey: @"EOStoredProcedureNameHintKey"];//TODO use it + model = [entity model]; + modelGroup = [model modelGroup]; //ret nil + //TODO if model gr + qualifier = [fetch qualifier]; // //Can be nil + + if (customQueryExpression) + { + [_adaptorChannel evaluateExpression: customQueryExpression]; + + NSAssert([propertiesToFetch count] > 0, @"No properties to fetch"); + + [_adaptorChannel setAttributesToFetch: propertiesToFetch]; + } + else + { + storedProcedure = [entity storedProcedureForOperation: + @"EOFetchWithPrimaryKeyProcedure"]; + + if (storedProcedure) + { + NSEmitTODO(); //TODO + + [self notImplemented: _cmd]; + } + + NSAssert([propertiesToFetch count] > 0, @"No properties to fetch"); + + NSDebugMLLog(@"gsdb", @"%@ -- %@ 0x%x: isFetchInProgress=%s", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + ([self isFetchInProgress] ? "YES" : "NO")); + + [_adaptorChannel selectAttributes: propertiesToFetch + fetchSpecification: fetch + lock: fetchLocksObjects + entity: entity]; + } + + NSDebugMLLog(@"gsdb", @"%@ -- %@ 0x%x: isFetchInProgress=%s", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + ([self isFetchInProgress] ? "YES" : "NO")); + +//TODO: verify +/* + if([_databaseContext updateStrategy] == EOUpdateWithPessimisticLocking + && ![[_databaseContext adaptorContext] transactionNestingLevel]) + [NSException raise:NSInvalidArgumentException + format:@"%@ -- %@ 0x%x: no transaction in progress", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + + if(_delegateRespondsTo.shouldSelectObjects) + { + if(![_delegate databaseContext:_databaseContext + shouldSelectObjectsWithFetchSpecification:fetch + databaseChannel:self]) + [NSException raise:EOGeneralDatabaseException + format:@"%@ -- %@ 0x%x: delegate refuses to select objects", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + }; + + [_fetchSpecifications addObject:fetch]; + + [self setCurrentEntity:[[_databaseContext database] + entityNamed:[fetch entityName]]];//done + [self setCurrentEditingContext:context];//done + + [self setIsLocking:([_databaseContext updateStrategy] == + EOUpdateWithPessimisticLocking ? + YES : + [fetch locksObjects])]; + [self setIsRefreshingObjects:[fetch refreshesRefetchedObjects]]; + + attributesToFetch = [_currentEntity attributesToFetch];//done + + NSDebugMLLog(@"gsdb",@"[_adaptorChannel class]: %@",[_adaptorChannel class]); + [_adaptorChannel selectAttributes:attributesToFetch + fetchSpecification:fetch + lock:_isLocking + entity:_currentEntity];//done + + [_fetchProperties addObjectsFromArray:attributesToFetch]; + + if(_delegateRespondsTo.didSelectObjects) + [_delegate databaseContext:_databaseContext + didSelectObjectsWithFetchSpecification:fetch + databaseChannel:self]; +*/ + + EOFLOGObjectFnStop(); +} + +@end /* EODatabaseChannel */ diff --git a/EOAccess/EODatabaseChannelPriv.h b/EOAccess/EODatabaseChannelPriv.h new file mode 100644 index 0000000..77e7e7c --- /dev/null +++ b/EOAccess/EODatabaseChannelPriv.h @@ -0,0 +1,48 @@ +/* + EODatabaseChannelPriv.h + + Copyright (C) 2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: Mars 2002 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EODatabaseChannelPriv_h__ +#define __EODatabaseChannelPriv_h__ + +@class NSArray; +@class EOFetchSpecification; +@class EOEditingContext; + + +@interface EODatabaseChannel (EODatabaseChannelPrivate) +- (NSArray*) _propertiesToFetch; +- (void)_setCurrentEntityAndRelationshipWithFetchSpecification: (EOFetchSpecification *)fetch; +-(void)_selectWithFetchSpecification: (EOFetchSpecification *)fetch + editingContext: (EOEditingContext *)context; +- (void) _buildNodeList: (id)param0 + withParent: (id)param1; +- (id) currentEditingContext; +- (void) _cancelInternalFetch; +- (void) _closeChannel; +- (void) _openChannel; +@end + +#endif /* __EODatabaseChannelPriv_h__ */ diff --git a/EOAccess/EODatabaseContext.h b/EOAccess/EODatabaseContext.h new file mode 100644 index 0000000..ab1865f --- /dev/null +++ b/EOAccess/EODatabaseContext.h @@ -0,0 +1,432 @@ +/* + EODatabaseContext.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: July 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EODatabaseContext_h__ +#define __EODatabaseContext_h__ + +#import + + +@class EOAdaptorContext; +@class EOAdaptorChannel; +@class EOAdaptorOperation; +@class EOEntity; +@class EOModel; +@class EORelationship; +@class EOAttribute; + +@class EODatabase; +@class EODatabaseChannel; +@class EODatabaseOperation; + + +typedef enum { + EOUpdateWithOptimisticLocking, + EOUpdateWithPessimisticLocking, + EOUpdateWithNoLocking +} EOUpdateStrategy; + +struct _EOTransactionScope; + +@interface EODatabaseContext : EOCooperatingObjectStore +{ + EODatabase *_database; + EOAdaptorContext *_adaptorContext; + EOUpdateStrategy _updateStrategy; +/*TOADD + NSMutableArray *_uniqueStack; + NSMutableArray *_deleteStack; + NSMutableArray *_modifiedObjects; +*/ + NSMutableArray *_registeredChannels; + NSMapTable *_dbOperationsByGlobalID; + EOObjectStoreCoordinator *_coordinator; // not retained + EOEditingContext *_editingContext; // not retained + id *_lockedObjects;//void* +/*TO ADD unsigned int _currentGeneration; + unsigned int _concurentFetches; +*/ + + unsigned int _numLocked;//TO REMOVE + NSMutableDictionary *_batchFaultBuffer; + NSMutableDictionary *_batchToManyFaultBuffer; + +// NSMutableDictionary *_snapshots; +// NSMutableDictionary *_toManySnapshots; + + EOEntity* _lastEntity; +/*TOADD + EOGlobalID *_currentGlobalID; + NSDictionary *_currentSnapshot; + objc_object *_currentBatch; +*/ + NSMutableArray *_uniqueStack;// snaps + NSMutableArray *_uniqueArrayStack;//to many snaps + NSMutableArray *_deleteStack; + + NSHashTable *_nonPrimaryKeyGenerators; + + struct { + unsigned int preparingForSave:1; + unsigned int beganTransaction:1; + unsigned int ignoreEntityCaching:1; + unsigned int _reserved:29; + } _flags; + id _delegate; // not retained + struct { + unsigned int willRunLoginPanelToOpenDatabaseChannel:1; + unsigned int newPrimaryKey:1; + unsigned int willPerformAdaptorOperations:1; + unsigned int shouldInvalidateObject:1; + unsigned int willOrderAdaptorOperations:1; + unsigned int shouldLockObject:1; + unsigned int shouldRaiseForLockFailure:1; + unsigned int shouldFetchObjects:1; + unsigned int didFetchObjects:1; + unsigned int shouldFetchObjectFault:1; + unsigned int shouldFetchArrayFault:1; + unsigned int _reserved:21; + } _delegateRespondsTo; + + NSRecursiveLock *_lock; //TODO: not lock object ! +} + ++ (EODatabaseContext *)databaseContextWithDatabase: (EODatabase *)database; + +- initWithDatabase: (EODatabase *)database; + ++ (EODatabaseContext *)registeredDatabaseContextForModel: (EOModel *)model + editingContext: (EOEditingContext *)editingContext; + ++ (Class)contextClassToRegister; ++ (void)setContextClassToRegister: (Class)contextClass; + +- (BOOL)hasBusyChannels; + +- (NSArray *)registeredChannels; + +- (void)registerChannel: (EODatabaseChannel *)channel; +- (void)unregisterChannel: (EODatabaseChannel *)channel; + +- (EODatabaseChannel *)_availableChannelFromRegisteredChannels; +- (EODatabaseChannel *)availableChannel; + +- (EODatabase *)database; + +- (EOObjectStoreCoordinator *)coordinator; + +- (EOAdaptorContext *)adaptorContext; + +- (void)setUpdateStrategy: (EOUpdateStrategy)strategy; +- (EOUpdateStrategy)updateStrategy; + +- (id)delegate; +- (void)setDelegate: (id)delegate; +- (void)handleDroppedConnection; +@end /* EODatabaseContext */ + + +@interface EODatabaseContext(EOObjectStoreSupport) + +- (id)faultForRawRow: (NSDictionary *)row + entityNamed: (NSString *)entityName + editingContext: (EOEditingContext *)editingContext; + +- (id)faultForGlobalID: (EOGlobalID *)globalID + editingContext: (EOEditingContext *)context; + +- (NSArray *)arrayFaultWithSourceGlobalID: (EOGlobalID *)globalID + relationshipName: (NSString *)name + editingContext: (EOEditingContext *)context; + +- (void)initializeObject: (id)object + withGlobalID: (EOGlobalID *)globalID + editingContext: (EOEditingContext *)context; + +- (NSArray *)objectsForSourceGlobalID: (EOGlobalID *)globalID + relationshipName: (NSString *)name + editingContext: (EOEditingContext *)context; +- (void)_registerSnapshot: (NSArray*)snapshot + forSourceGlobalID: (EOGlobalID*)globalID + relationshipName: (NSString*)name + editingContext: (EOEditingContext*)context; + +- (void)refaultObject: object + withGlobalID: (EOGlobalID *)globalID + editingContext: (EOEditingContext *)context; + +- (void)saveChangesInEditingContext: (EOEditingContext *)context; + +- (NSArray *)objectsWithFetchSpecification: (EOFetchSpecification *)fetchSpecification + editingContext:(EOEditingContext *)context; + +- (BOOL)isObjectLockedWithGlobalID: (EOGlobalID *)gid + editingContext: (EOEditingContext *)context; + +- (void)lockObjectWithGlobalID: (EOGlobalID *)gid + editingContext: (EOEditingContext *)context; + +- (void)invalidateAllObjects; +- (void)invalidateObjectsWithGlobalIDs: (NSArray *)globalIDs; + +@end + + +@interface EODatabaseContext(EOCooperatingObjectStoreSupport) + +- (BOOL)ownsGlobalID:(EOGlobalID *)globalID; + +- (BOOL)ownsObject: (id)object; + +- (BOOL)ownsEntityNamed: (NSString *)entityName; + +- (BOOL)handlesFetchSpecification: (EOFetchSpecification *)fetchSpecification; + +- (void)prepareForSaveWithCoordinator: (EOObjectStoreCoordinator *)coordinator + editingContext: (EOEditingContext *)context; + +/** The method overrides the inherited implementation to create a list of EODatabaseOperations for EOEditingContext objects changes (only objects owned by the receiver). +It forwards any relationship changes found which are not owned by the receiver to the EOObjectStoreCoordinator. +It's invoked during EOObjectStoreCoordinator saving changes (saveChangesInEditingContext:) method. +It's invoked after prepareForSaveWithCoordinator:editingContext: and before ownsGlobalID:. +**/ +- (void)recordChangesInEditingContext; + +- (void)recordUpdateForObject: object + changes: (NSDictionary *)changes; + +- (void)performChanges; + +- (void)commitChanges; + +- (void)rollbackChanges; + +- (NSDictionary *)valuesForKeys: (NSArray *)keys object: object; + +-(void)relayPrimaryKey: (NSDictionary*)pk + object: (id)object + entity: (EOEntity*)entity; + +-(void)nullifyAttributesInRelationship: (EORelationship*)relationship + sourceObject: (id)sourceObject + destinationObjects: (NSArray*)destinationObjects; +-(void)nullifyAttributesInRelationship: (EORelationship*)relationship + sourceObject: (id)sourceObject + destinationObject: (id)destinationObject; +-(void)relayAttributesInRelationship: (EORelationship*)relationship + sourceObject: (id)sourceObject + destinationObjects: (NSArray*)destinationObjects; +-(NSDictionary*)relayAttributesInRelationship: (EORelationship*)relationship + sourceObject: (id)sourceObject + destinationObject: (id)destinationObject; + +- (id) databaseOperationForObject: (id)param0; +- (id) databaseOperationForGlobalID: (id)param0; +- (void) recordDatabaseOperation: (id)param0; +- (void) recordDeleteForObject: (id)param0; +- (void) recordInsertForObject: (id)param0; + +- (void) createAdaptorOperationsForDatabaseOperation: (EODatabaseOperation*)dbOpe + attributes: (NSArray*)attributes; +- (void) createAdaptorOperationsForDatabaseOperation: (EODatabaseOperation*)dbOpe; +- (NSArray*) orderAdaptorOperations; + +- (id) entitiesOnWhichThisEntityDepends: (EOEntity *)entity; +-(NSArray*)entityNameOrderingArrayForEntities: (NSArray *)entities; + +- (BOOL) isValidQualifierTypeForAttribute: (EOAttribute*)attribute; +- (id) lockingNonQualifiableAttributes: (NSArray*)attributes; +- (NSArray*) lockingAttributesForAttributes: (NSArray*)attributes + entity: (EOEntity*)enity; +- (NSArray*) primaryKeyAttributesForAttributes: (NSArray*)attributes + entity: (EOEntity*)entity; +- (EOQualifier*) qualifierForLockingAttributes: (NSArray*)attributes + primaryKeyAttributes: (NSArray*)primaryKeyAttributes + entity: (EOEntity*)entity + snapshot: (NSDictionary*)snapshot; +- (void) insertEntity: (EOEntity*)entity + intoOrderingArray: (NSMutableArray*)orderingArray + withDependencies: (NSDictionary*)dependencies + processingSet: (NSMutableSet*)processingSet; +- (void) processSnapshotForDatabaseOperation: (EODatabaseOperation*)dbOpe; + +- (NSDictionary*) valuesToWriteForAttributes: (NSArray*)attributes + entity: (EOEntity*)entity + changedValues: (NSDictionary*)changedValues; + +@end + + +@interface EODatabaseContext(EOBatchFaulting) + +- (void)batchFetchRelationship: (EORelationship *)relationship + forSourceObjects: (NSArray *)objects + editingContext: (EOEditingContext *)editingContext; + +@end + + +@interface EODatabaseContext (EODatabaseSnapshotting) + +- (void)recordSnapshot: (NSDictionary *)snapshot + forGlobalID: (EOGlobalID *)gid; + + +/** Returns snapshot for globalID. (nil if there's no snapshot for the globalID or if the corresponding +tsimestamp is less than ti). +Searches first locally (in the transaction scope) and after in the EODatabase. **/ + +- (NSDictionary *)snapshotForGlobalID: (EOGlobalID *)gid + after: (NSTimeInterval)ti; + +/** Returns snapshot for globalID by calling snapshotForGlobalID:after: with EODistantPastTimeInterval +as time interval. +Searches first locally (in the transaction scope) and after in the EODatabase. **/ +- (NSDictionary *)snapshotForGlobalID: (EOGlobalID *)gid; + +- (void)recordSnapshot: (NSArray *)gids + forSourceGlobalID: (EOGlobalID *)gid + relationshipName: (NSString *)name; + +- (NSArray *)snapshotForSourceGlobalID: (EOGlobalID *)gid + relationshipName: (NSString *)name; + +/** Returns the snapshot for the globalID (nil if there's none). +Only searches locally (in the transaction scope), not in the EODatabase. **/ + +- (NSDictionary *)localSnapshotForGlobalID: (EOGlobalID *)gid; + +- (NSArray *)localSnapshotForSourceGlobalID: (EOGlobalID *)gid + relationshipName:(NSString *)name; + +- (void)forgetSnapshotForGlobalID: (EOGlobalID *)gid; +- (void)forgetSnapshotsForGlobalIDs: (NSArray *)gids; + +- (void)recordSnapshots: (NSDictionary *)snapshots; + +- (void)recordToManySnapshots: (NSDictionary *)snapshots; + +- (void)registerLockedObjectWithGlobalID: (EOGlobalID *)globalID; +- (BOOL)isObjectLockedWithGlobalID: (EOGlobalID *)globalID; +- (void)forgetAllLocks; +- (void)forgetLocksForObjectsWithGlobalIDs: (NSArray *)gids; +- (void) _rollbackTransaction; +- (void) _commitTransaction; +- (void) _beginTransaction; +- (EODatabaseChannel*) _obtainOpenChannel; +- (BOOL) _openChannelWithLoginPanel:(id)param0; +- (void) _forceDisconnect; +- (void)initializeObject:(id)object + row:(NSDictionary*)row + entity:(EOEntity*)entity + editingContext:(EOEditingContext*)context; + +@end + +@interface EODatabaseContext(EOMultiThreaded) + +- (void)lock; +- (void)unlock; + +@end + +// Notifications: +extern NSString *EODatabaseChannelNeededNotification; + + +@interface NSObject (EODatabaseContextDelegation) + +- (BOOL)databaseContext: (EODatabaseContext *)context +willRunLoginPanelToOpenDatabaseChannel: (EODatabaseChannel *)channel; + +- (NSDictionary *)databaseContext: (EODatabaseContext *)context + newPrimaryKeyForObject: (id)object + entity: (EOEntity *)entity; + +- (BOOL)databaseContext: (EODatabaseContext *)context + failedToFetchObject: (id)object + globalID: (EOGlobalID *)gid; + +- (NSArray *)databaseContext: (EODatabaseContext *)context +willOrderAdaptorOperationsFromDatabaseOperations: (NSArray *)databaseOps; + +- (NSArray *)databaseContext: (EODatabaseContext *)context +willPerformAdaptorOperations: (NSArray *)adaptorOps + adaptorChannel: (EOAdaptorChannel *)adaptorChannel; + +- (BOOL)databaseContext: (EODatabaseContext *)context +shouldInvalidateObjectWithGlobalID: (EOGlobalID *)globalId + snapshot: (NSDictionary *)snapshot; + +- (NSArray *)databaseContext: (EODatabaseContext *)context +shouldFetchObjectsWithFetchSpecification: (EOFetchSpecification *)fetchSpecification + editingContext: (EOEditingContext *)editingContext; + +- (void)databaseContext: (EODatabaseContext *)context + didFetchObjects: (NSArray *)objects + fetchSpecification: (EOFetchSpecification *)fetchSpecification + editingContext: (EOEditingContext *)editingContext; + +- (BOOL)databaseContext: (EODatabaseContext *)context +shouldSelectObjectsWithFetchSpecification: (EOFetchSpecification *)fetchSpecification + databaseChannel: (EODatabaseChannel *)channel; + +- (BOOL)databaseContext: (EODatabaseContext *)context +shouldUsePessimisticLockWithFetchSpecification: (EOFetchSpecification *)fetchSpecification + databaseChannel: (EODatabaseChannel *)channel; + +- (void)databaseContext: (EODatabaseContext *)context +didSelectObjectsWithFetchSpecification: (EOFetchSpecification *)fetchSpecification + databaseChannel: (EODatabaseChannel *)channel; + +- (NSDictionary *)databaseContext: (EODatabaseContext *)context + shouldUpdateCurrentSnapshot: (NSDictionary *)currentSnapshot + newSnapshot: (NSDictionary *)newSnapshot + globalID: (EOGlobalID *)globalID + databaseChannel: (EODatabaseChannel *)channel; + +- (BOOL)databaseContext: (EODatabaseContext *)databaseContext +shouldLockObjectWithGlobalID: (EOGlobalID *)globalID + snapshot: (NSDictionary *)snapshot; + +- (BOOL)databaseContext: (EODatabaseContext *)databaseContext +shouldRaiseExceptionForLockFailure: (NSException *)exception; + +- (BOOL)databaseContext: (EODatabaseContext *)databaseContext + shouldFetchObjectFault: (id)fault; + +- (BOOL)databaseContext: (EODatabaseContext *)databaseContext + shouldFetchArrayFault: (id)fault; + +@end + +extern NSString *EOCustomQueryExpressionHintKey; + +extern NSString *EODatabaseContextKey; +extern NSString *EODatabaseOperationsKey; +extern NSString *EOFailedDatabaseOperationKey; + +#endif /* __EODatabaseContext_h__ */ diff --git a/EOAccess/EODatabaseContext.m b/EOAccess/EODatabaseContext.m new file mode 100644 index 0000000..d9b5e45 --- /dev/null +++ b/EOAccess/EODatabaseContext.m @@ -0,0 +1,6670 @@ +/** + EODatabaseContext.m EODatabaseContext Class + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: June 2000 + + Author: Manuel Guesdon + Date: October 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import + +#import +#import +#import +#import +#import +#import +#import +#import + +#import +#import + +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#import +#import +#import +#import +#import +#import +#import + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + + +#define _LOCK_BUFFER 128 + + +NSString *EODatabaseChannelNeededNotification = @"EODatabaseChannelNeededNotification"; + +NSString *EODatabaseContextKey = @"EODatabaseContextKey"; +NSString *EODatabaseOperationsKey = @"EODatabaseOperationsKey"; +NSString *EOFailedDatabaseOperationKey = @"EOFailedDatabaseOperationKey"; + + +@implementation EODatabaseContext + +// Initializing instances + +static Class _contextClass = Nil; + ++ (void)load +{ + [[NSNotificationCenter defaultCenter] + addObserver: self + selector: @selector(_registerDatabaseContext:) + name: EOCooperatingObjectStoreNeeded + object: nil]; +} + ++ (void)initialize +{ + if (!_contextClass) + _contextClass = [EODatabaseContext class]; +} + ++ (EODatabaseContext*)databaseContextWithDatabase: (EODatabase *)database +{ + return [[[self alloc] initWithDatabase: database] autorelease]; +} + ++ (void)_registerDatabaseContext:(NSNotification *)notification +{ + EOObjectStoreCoordinator *coordinator = [notification object]; + EODatabaseContext *dbContext = nil; + EOModel *model = nil; + NSString *entityName = nil; + id keyValue = nil; + + keyValue = [[notification userInfo] objectForKey: @"globalID"]; + + if (keyValue == nil) + keyValue = [[notification userInfo] objectForKey: @"fetchSpecification"]; + + if (keyValue == nil) + keyValue = [[notification userInfo] objectForKey: @"object"]; + + if (keyValue) + entityName = [keyValue entityName]; + + model = [[[EOModelGroup defaultGroup] entityNamed:entityName] model]; + + dbContext = [EODatabaseContext databaseContextWithDatabase: + [EODatabase databaseWithModel: model]]; + + [coordinator addCooperatingObjectStore:dbContext]; +} + +- (void) registerForAdaptorContextNotifications: (EOAdaptorContext*)adaptorContext +{ + //OK + [[NSNotificationCenter defaultCenter] + addObserver: self + selector: @selector(_beginTransaction) + name: EOAdaptorContextBeginTransactionNotification + object: adaptorContext]; + [[NSNotificationCenter defaultCenter] + addObserver: self + selector: @selector(_commitTransaction) + name: EOAdaptorContextCommitTransactionNotification + object: adaptorContext]; + + [[NSNotificationCenter defaultCenter] + addObserver: self + selector: @selector(_rollbackTransaction) + name: EOAdaptorContextRollbackTransactionNotification + object: adaptorContext]; +} + +- (id) initWithDatabase: (EODatabase *)database +{ + //OK + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"database=%p",database); + + if ((self = [super init])) + { + _adaptorContext = [[[database adaptor] createAdaptorContext] retain]; + + if (_adaptorContext == nil) + { + NSLog(@"EODatabaseContext could not create adaptor context"); + [self autorelease]; + + return nil; + } + _database = [database retain]; + + // Register this object into database + [_database registerContext: self]; + [self setUpdateStrategy: EOUpdateWithOptimisticLocking]; + + _uniqueStack = [NSMutableArray new]; + _deleteStack = [NSMutableArray new]; + _uniqueArrayStack = [NSMutableArray new]; + + _registeredChannels = [NSMutableArray new]; + _batchFaultBuffer = [NSMutableDictionary new]; + _batchToManyFaultBuffer = [NSMutableDictionary new]; + + // We want to know when snapshots change in database + [[NSNotificationCenter defaultCenter] + addObserver: self + selector: @selector(_snapshotsChangedInDatabase:) + name: EOObjectsChangedInStoreNotification + object: _database]; + + // We want to know when objects change + [[NSNotificationCenter defaultCenter] + addObserver: self + selector: @selector(_objectsChanged:) + name: EOObjectsChangedInStoreNotification + object: self]; + + [self registerForAdaptorContextNotifications: _adaptorContext]; + +//??? +/*NO _snapshots = [NSMutableDictionary new]; + _toManySnapshots = [NSMutableDictionary new]; +*/ + + + + +//NO _lock = [NSRecursiveLock new]; + +//NO _numLocked = 0; +//After _lockedObjects = NSZoneMalloc(NULL, _LOCK_BUFFER*sizeof(id)); + + + + /* //TODO ? + transactionStackTop = NULL; + transactionNestingLevel = 0; + isKeepingSnapshots = YES; + isUniquingObjects = [database uniquesObjects]; + [database contextDidInit:self];*/ + } + + EOFLOGObjectFnStop(); + + return self; +} + +- (void)_snapshotsChangedInDatabase: (NSNotification *)notification +{ + //OK EOObjectsChangedInStoreNotification EODatabase + EOFLOGObjectFnStart(); + + if ([notification object] == _database)//?? + [[NSNotificationCenter defaultCenter] + postNotificationName: [notification name] + object: self + userInfo: [notification userInfo]];//==> _objectsChanged + + EOFLOGObjectFnStop(); +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver: self]; + + [_database unregisterContext: self]; + + DESTROY(_adaptorContext); + DESTROY(_database); + + if (_dbOperationsByGlobalID) + { + NSDebugMLog(@"MEMORY: dbOperationsByGlobalID count=%u",NSCountMapTable(_dbOperationsByGlobalID)); + NSFreeMapTable(_dbOperationsByGlobalID); + _dbOperationsByGlobalID = NULL; + } +/*NO + DESTROY(_snapshots); + DESTROY(_toManySnapshots); +*/ + DESTROY(_uniqueStack); + DESTROY(_deleteStack); + DESTROY(_uniqueArrayStack); + + DESTROY(_registeredChannels); + + DESTROY(_batchFaultBuffer); + DESTROY(_batchToManyFaultBuffer); + + DESTROY(_lastEntity); + + if (_nonPrimaryKeyGenerators) + { + NSDebugMLog(@"MEMORY: dbOperationsByGlobalID count=%u", + NSCountMapTable(_dbOperationsByGlobalID)); + + NSFreeHashTable(_nonPrimaryKeyGenerators); + _nonPrimaryKeyGenerators = NULL; + } + + if (_lockedObjects) + NSZoneFree(NULL, _lockedObjects); // Turbocat + + DESTROY(_lock); + + [super dealloc]; +} + ++ (EODatabaseContext *)registeredDatabaseContextForModel: (EOModel *)model + editingContext: (EOEditingContext *)editingContext +{ + EOObjectStoreCoordinator *edObjectStore; + NSArray *cooperatingObjectStores; + NSEnumerator *storeEnum; + EOCooperatingObjectStore *coObjectStore; + EODatabase *anDatabase; + NSArray *models; + EODatabaseContext *dbContext = nil; + + EOFLOGClassFnStartOrCond2(@"DatabaseLevel", @"EODatabaseContext"); + + if (model && editingContext) + { + edObjectStore = (EOObjectStoreCoordinator *)[editingContext rootObjectStore]; + cooperatingObjectStores = [edObjectStore cooperatingObjectStores]; // get all EODatabaseContexts + + storeEnum = [cooperatingObjectStores objectEnumerator]; + + while ((coObjectStore = [storeEnum nextObject])) + { + if ([coObjectStore isKindOfClass: [EODatabaseContext class]]) + { + anDatabase = [(EODatabaseContext *)coObjectStore database]; + + if (anDatabase && (models = [anDatabase models])) + { + if ([models containsObject: model]) + { + dbContext = (EODatabaseContext *)coObjectStore; + break; + } + } + } + } + + if (!dbContext) + { + // no EODatabaseContext found, create a new one + dbContext = [EODatabaseContext databaseContextWithDatabase: + [EODatabase databaseWithModel: + model]]; + + if (dbContext) + { + [edObjectStore addCooperatingObjectStore: dbContext]; + } + } + } + + EOFLOGClassFnStopOrCond2(@"DatabaseLevel", @"EODatabaseContext"); + + return dbContext; +} + + ++ (Class)contextClassToRegister +{ + NSEmitTODO(); + // TODO; + return _contextClass; +} + ++ (void)setContextClassToRegister: (Class)contextClass +{ + _contextClass = contextClass; +} + +/** Returns YES if we have at least one busy channel **/ +- (BOOL)hasBusyChannels +{ + BOOL busy = NO; + int i = 0; + int count = 0; + + count = [_registeredChannels count]; + + for (i = 0 ; !busy && i < count; i++) + { + EODatabaseChannel *channel = [[_registeredChannels objectAtIndex: i] + nonretainedObjectValue]; + + busy = [channel isFetchInProgress]; + } + + return busy; +} + +- (NSArray *)registeredChannels +{ + NSMutableArray *array = nil; + int i, count; + + count = [_registeredChannels count]; + array = [NSMutableArray arrayWithCapacity: count]; + + for (i = 0; i < count; i++) + [array addObject: [[_registeredChannels objectAtIndex: i] + nonretainedObjectValue]]; + + return array; +} + +- (void)registerChannel: (EODatabaseChannel *)channel +{ +//call channel databaseContext +//test if not exists _registeredChannels indexOfObjectIdenticalTo:channel + NSLog(@"** REGISTER channel ** debug:%d ** total registered:%d", + [[channel adaptorChannel] isDebugEnabled], + [_registeredChannels count] + 1); + + [_registeredChannels addObject: + [NSValue valueWithNonretainedObject: channel]]; + [channel setDelegate: nil]; +} + +- (void)unregisterChannel: (EODatabaseChannel *)channel +{ + int i; + + for (i = [_registeredChannels count] - 1; i >= 0; i--) + { + if ([[_registeredChannels objectAtIndex: i] + nonretainedObjectValue] == channel) + { + [_registeredChannels removeObjectAtIndex: i]; + break; + } + } +} + +/** returns a non busy channel if any, nil otherwise **/ +-(EODatabaseChannel *)_availableChannelFromRegisteredChannels +{ + NSEnumerator *channelsEnum; + NSValue *channel = nil; + + channelsEnum = [_registeredChannels objectEnumerator]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"REGISTERED CHANNELS nb=%d", + [_registeredChannels count]); + + while ((channel = [channelsEnum nextObject])) + { + if ([(EODatabaseChannel *)[channel nonretainedObjectValue] + isFetchInProgress] == NO) + { + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"CHANNEL %p is not busy", + [channel nonretainedObjectValue]); + + return [channel nonretainedObjectValue]; + } + else + { + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"CHANNEL %p is busy", + [channel nonretainedObjectValue]); + } + } + + return nil; +} + +/** return a non busy channel **/ +- (EODatabaseChannel *)availableChannel +{ + EODatabaseChannel *channel = nil; + int num = 2; + + while (!channel && num) + { + channel = [self _availableChannelFromRegisteredChannels]; + + if (!channel) + { + //If not channel and last try: send a EODatabaseChannelNeededNotification notification before this last try + if (--num) + [[NSNotificationCenter defaultCenter] + postNotificationName: EODatabaseChannelNeededNotification + object: self]; + } + } + + if (!channel) + channel = [EODatabaseChannel databaseChannelWithDatabaseContext: self]; + + return channel; +} + +/** returns the database **/ +- (EODatabase *)database +{ + return _database; +} + +/** returns the coordinator **/ +- (EOObjectStoreCoordinator *)coordinator +{ + return _coordinator; +} + +/** returns the adaptor context **/ +- (EOAdaptorContext *)adaptorContext +{ + return _adaptorContext; +} + +/** Set the update strategy to 'strategy' +May raise an exception if transaction has began or if you want pessimistic lock when there's already a snapshot recorded +**/ +- (void)setUpdateStrategy: (EOUpdateStrategy)strategy +{ + if (_flags.beganTransaction) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: transaction in progress", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + + //Can't set pessimistic locking where there's already snapshosts ! + if (strategy == EOUpdateWithPessimisticLocking + && [_database snapshots]) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: can't set EOUpdateWithPessimisticLocking when receive's EODatabase already has snapshots", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + + _updateStrategy = strategy; +} + +/** Get the update strategy **/ +- (EOUpdateStrategy)updateStrategy +{ + return _updateStrategy; +} + +/** Get the delegate **/ +- (id)delegate +{ + return _delegate; +} + +/** Set the delegate **/ +- (void)setDelegate:(id)delegate +{ + NSEnumerator *channelsEnum = [_registeredChannels objectEnumerator]; + EODatabaseChannel *channel = nil; + + _delegate = delegate; + + _delegateRespondsTo.willRunLoginPanelToOpenDatabaseChannel = + [delegate respondsToSelector: @selector(databaseContext:willRunLoginPanelToOpenDatabaseChannel:)]; + _delegateRespondsTo.newPrimaryKey = + [delegate respondsToSelector: @selector(databaseContext:newPrimaryKeyForObject:entity:)]; + _delegateRespondsTo.willPerformAdaptorOperations = + [delegate respondsToSelector: @selector(databaseContext:willPerformAdaptorOperations:adaptorChannel:)]; + _delegateRespondsTo.shouldInvalidateObject = + [delegate respondsToSelector: @selector(databaseContext:shouldInvalidateObjectWithGlobalID:snapshot:)]; + _delegateRespondsTo.willOrderAdaptorOperations = + [delegate respondsToSelector: @selector(databaseContext:willOrderAdaptorOperationsFromDatabaseOperations:)]; + _delegateRespondsTo.shouldLockObject = + [delegate respondsToSelector: @selector(databaseContext:shouldLockObjectWithGlobalID:snapshot:)]; + _delegateRespondsTo.shouldRaiseForLockFailure = + [delegate respondsToSelector: @selector(databaseContext:shouldRaiseExceptionForLockFailure:)]; + _delegateRespondsTo.shouldFetchObjects = + [delegate respondsToSelector: @selector(databaseContext:shouldFetchObjectsWithFetchSpecification:editingContext:)]; + _delegateRespondsTo.didFetchObjects = + [delegate respondsToSelector: @selector(databaseContext:didFetchObjects:fetchSpecification:editingContext:)]; + _delegateRespondsTo.shouldFetchObjectFault = + [delegate respondsToSelector: @selector(databaseContext:shouldFetchObjectsWithFetchSpecification:editingContext:)]; + _delegateRespondsTo.shouldFetchArrayFault = + [delegate respondsToSelector: @selector(databaseContext:shouldFetchArrayFault:)]; + + while ((channel == [channelsEnum nextObject])) + [channel setDelegate: delegate]; +} + +- (void)handleDroppedConnection +{ + int i; + + EOFLOGObjectFnStartOrCond2(@"DatabaseLevel", @"EODatabaseContext"); + + DESTROY(_adaptorContext); + + for (i = [_registeredChannels count] - 1; i >= 0; i--) + { + [(EODatabaseChannel *)[[_registeredChannels objectAtIndex: i] + nonretainedObjectValue] release]; + } + + DESTROY(_registeredChannels); + + _adaptorContext = [[[[self database] adaptor] createAdaptorContext] retain]; + _registeredChannels = [NSMutableArray new]; + + EOFLOGObjectFnStopOrCond2(@"DatabaseLevel", @"EODatabaseContext"); +} + +@end + + +@implementation EODatabaseContext(EOObjectStoreSupport) + +/** Return a fault for row 'row' **/ +- (id)faultForRawRow: (NSDictionary *)row + entityNamed: (NSString *)entityName + editingContext: (EOEditingContext *)context +{ + EOEntity *entity; + EOGlobalID *gid; + id object; + + EOFLOGObjectFnStart(); + + entity = [_database entityNamed: entityName]; + gid = [entity globalIDForRow: row]; + + object = [self faultForGlobalID: gid + editingContext: context]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"object=%p of class (%@)", + object, [object class]); + + EOFLOGObjectFnStop(); + + return object; +} + +/** return entity corresponding to 'globalID' **/ +- (id) entityForGlobalID: (EOGlobalID *)globalID +{ + //OK + NSString *entityName; + EOEntity *entity; + + DESTROY(_lastEntity); + + entityName = [globalID entityName]; + entity = [_database entityNamed: entityName]; + + ASSIGN(_lastEntity, entity); + + return entity; +} + +/** Make object a fault **/ +- (void) _turnToFault: (id)object + gid: (EOGlobalID *)globalID + editingContext: (EOEditingContext *)context + isComplete: (BOOL)isComplete +{ + //OK + EOAccessFaultHandler *handler; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"object=%p", object); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"globalID=%@", globalID); + + NSAssert(globalID, @"No globalID"); + NSAssert1([globalID isKindOfClass: [EOKeyGlobalID class]], + @"globalID is not a EOKeyGlobalID but a %@", + [globalID class]); + + if ([(EOKeyGlobalID*)globalID areKeysAllNulls]) + NSWarnLog(@"All key of globalID %p (%@) are nulls", + globalID, + globalID); + + handler = [EOAccessFaultHandler + accessFaultHandlerWithGlobalID: (EOKeyGlobalID*)globalID + databaseContext: self + editingContext: context]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"handler=%@", handler); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"object->isa=%p", object->isa); + + [EOFault makeObjectIntoFault: object + withHandler: handler]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"object->isa=%p", object->isa); + + [self _addBatchForGlobalID: (EOKeyGlobalID*)globalID + fault: object]; + + EOFLOGObjectFnStop(); + //TODO: use isComplete +} + +/** Get a fault for 'globalID' **/ +- (id)faultForGlobalID: (EOGlobalID *)globalID + editingContext: (EOEditingContext *)context +{ + //Seems OK + EOClassDescription *classDescription = nil; + EOEntity *entity; + id object = nil; + BOOL isFinal; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"globalID=%@", globalID); + + isFinal = [(EOKeyGlobalID *)globalID isFinal]; + entity = [self entityForGlobalID: globalID]; + + NSAssert(entity, @"no entity"); + + classDescription = [entity classDescriptionForInstances]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"classDescription=%@", + classDescription); + + object = [classDescription createInstanceWithEditingContext: context + globalID: globalID + zone: NULL]; + + NSAssert1(object, @"No Object. classDescription=%@", classDescription); +/*mirko: NO + NSDictionary *pk; + NSEnumerator *pkEnum; + NSString *pkKey; + NSArray *classPropertyNames; +classPropertyNames = [entity classPropertyNames]; + pk = [entity primaryKeyForGlobalID:(EOKeyGlobalID *)globalID]; + pkEnum = [pk keyEnumerator]; + while ((pkKey = [pkEnum nextObject])) + { + if ([classPropertyNames containsObject:pkKey] == YES) + [obj takeStoredValue:[pk objectForKey:pkKey] + forKey:pkKey]; + } +*/ + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"object=%p", object); + + if ([(EOKeyGlobalID *)globalID areKeysAllNulls]) + NSWarnLog(@"All key of globalID %p (%@) are nulls", + globalID, + globalID); + + [self _turnToFault: object + gid: globalID + editingContext: context + isComplete: isFinal];//?? + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"Record Object"); + + [context recordObject: object + globalID: globalID]; + + EOFLOGObjectFnStop(); + + return object; +} + +/** Get an array fault for globalID for relationshipName **/ +- (NSArray *)arrayFaultWithSourceGlobalID: (EOGlobalID *)globalID + relationshipName: (NSString *)relationshipName + editingContext: (EOEditingContext *)context +{ + //Seems OK + NSArray *obj = nil; + + if (![globalID isKindOfClass: [EOKeyGlobalID class]]) + { + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ The globalID %@ must be an EOKeyGlobalID to be able to construct a fault", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + globalID]; + } + else + { + EOAccessArrayFaultHandler *handler = nil; + + obj = [EOCheapCopyMutableArray array]; + handler = [EOAccessArrayFaultHandler + accessArrayFaultHandlerWithSourceGlobalID: + (EOKeyGlobalID*)globalID + relationshipName: relationshipName + databaseContext: self + editingContext: context]; + + [EOFault makeObjectIntoFault: obj + withHandler: handler]; + + [self _addToManyBatchForSourceGlobalID: (EOKeyGlobalID *)globalID + relationshipName: relationshipName + fault: (EOFault*)obj]; + } + + return obj; +} + +- (void)initializeObject: (id)object + withGlobalID: (EOGlobalID *)globalID + editingContext: (EOEditingContext *)context +{ +//near OK + EOEntity *entity = nil; + + EOFLOGObjectFnStart(); + + if ([globalID isTemporary]) + { + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + } + + if (![globalID isFinal]) + { + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + } + + //mirko: + if (_updateStrategy == EOUpdateWithPessimisticLocking) + [self registerLockedObjectWithGlobalID: globalID]; + + entity = [self entityForGlobalID: globalID]; + +/*Mirko: + if ([object respondsToSelector:@selector(entity)]) + entity = [object entity]; + else + entity = [_database entityNamed:[globalID entityName]]; +*/ + + [self initializeObject: object + row: [self snapshotForGlobalID: globalID] //shound be _currentSnapshot + entity: entity + editingContext: context]; + + EOFLOGObjectFnStop(); +} + +- (void) _objectsChanged: (NSNotification*)notification +{ + EOFLOGObjectFnStart(); + +/*object==self EOObjectsChangedInStoreNotification +userInfo = { + deleted = (List Of GlobalIDs); + inserted = (List Of GlobalIDs); + updated = (List Of GlobalIDs); +*/ + + if ([notification object] != self) + { + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + } + else + { + //OK for update + //TODO-NOW for insert/delete + NSDictionary *userInfo = [notification userInfo]; + NSArray *updatedObjects = [userInfo objectForKey: @"updated"]; + //NSArray *insertedObjects = [userInfo objectForKey: @"inserted"]; + //NSArray *deletedObjects = [userInfo objectForKey: @"deleted"]; + int i, count = [updatedObjects count]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"updatedObjects=%@", + updatedObjects); + + for (i = 0; i < count; i++) + { + EOKeyGlobalID *gid=[updatedObjects objectAtIndex: i]; + NSString *entityName; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"gid=%@", gid); + + entityName = [gid entityName]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"entityName=%@", + entityName); + + [_database invalidateResultCacheForEntityNamed: entityName]; + } + } + + EOFLOGObjectFnStop(); +} + +- (void) _snapshotsChangedInDatabase: (NSNotification*)notification +{ + EOFLOGObjectFnStart(); + +/* + userInfo = { + deleted = (List Of GlobalIDs); + inserted = (List Of GlobalIDs); + updated = (List Of GlobalIDs); +}} +*/ + + if ([notification object] != self) + { + [[NSNotificationCenter defaultCenter] + postNotificationName: EOObjectsChangedInStoreNotification + object: self + userInfo: [notification userInfo]]; +//call _objectsChanged: and ObjectStoreCoordinator _objectsChangedInSubStore: + } + + EOFLOGObjectFnStop(); +} + +- (NSArray *)objectsForSourceGlobalID: (EOGlobalID *)globalID + relationshipName: (NSString *)name + editingContext: (EOEditingContext *)context +{ + //Near OK + NSArray *objects = nil; + id sourceObjectFault = nil; + id relationshipValue = nil; + NSArray *sourceSnapshot = nil; + int sourceSnapshotCount = 0; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"globalID=%@", globalID); + + //First get the id from which we search the source object + sourceObjectFault = [context faultForGlobalID: globalID + editingContext: context]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"sourceObjectFault %p=%@", + sourceObjectFault, sourceObjectFault); + + // Get the fault value from source object + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"relationshipName=%@", name); + + relationshipValue = [sourceObjectFault storedValueForKey: name]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"relationshipValue %p=%@", + relationshipValue, relationshipValue); + + //Try to see if there is a snapshot for the source object + sourceSnapshot = [_database snapshotForSourceGlobalID: globalID + relationshipName: name]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"sourceSnapshot %p (%@)=%@", + sourceSnapshot, [sourceSnapshot class], + sourceSnapshot); + + sourceSnapshotCount = [sourceSnapshot count]; + + if (sourceSnapshotCount > 0) + { + EOGlobalID *snapGID = nil; + id snapFault = nil; + int i; + + [EOFault clearFault: relationshipValue]; + + for (i = 0; i < sourceSnapshotCount; i++) + { + snapGID = [sourceSnapshot objectAtIndex: i]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"snapGID=%@", snapGID); + + snapFault = [context faultForGlobalID: snapGID + editingContext: context]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"snapFault=%@", + snapFault); + + [relationshipValue addObject: snapFault]; + } + + objects = relationshipValue; + } + else + { + EOEntity *entity; + EORelationship *relationship; + unsigned int maxBatch = 0; + BOOL isToManyToOne = NO; + EOEntity *destinationEntity = nil; + EOModel *destinationEntityModel = nil; + NSArray *models = nil; + EOQualifier *auxiliaryQualifier = nil; + NSDictionary *contextSourceSnapshot = nil; + id sourceObject = nil; + EORelationship *inverseRelationship = nil; + EOEntity *invRelEntity = nil; + NSArray *invRelEntityClassProperties = nil; + NSString *invRelName = nil; + EOQualifier *qualifier = nil; + EOFetchSpecification *fetchSpec = nil; + + // Get the source object entity + entity = [self entityForGlobalID: globalID]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"entity name=%@", + [entity name]); + + //Get the relationship named 'name' + relationship = [entity relationshipNamed: name]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"relationship=%@", + relationship); + + //Get the max number of fault to fetch + maxBatch = [relationship numberOfToManyFaultsToBatchFetch]; + + isToManyToOne = [relationship isToManyToOne];//NO + + if (isToManyToOne) + { + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO if isToManyToOne + } + + //Get the fault entity (aka relationsip destination entity) + destinationEntity = [relationship destinationEntity]; + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"destinationEntity name=%@", + [destinationEntity name]); + + //Get the destination entity model + destinationEntityModel = [destinationEntity model]; + + //and _database model to verify if the destinationEntityModel is in database models + models = [_database models]; + + if ([models indexOfObjectIdenticalTo: destinationEntityModel] + == NSNotFound) + { + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO error + } + + //Get the relationship qualifier if any + auxiliaryQualifier = [relationship auxiliaryQualifier];//nil + + if (auxiliaryQualifier) + { + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO if auxqualif + } + + //?? + contextSourceSnapshot = [self snapshotForGlobalID: globalID]; + + NSEmitTODO(); + //TODO Why first asking for faultForGlobalID and now asking objectForGlobalID ?? + + sourceObject = [context objectForGlobalID: globalID]; + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"sourceObject=%@", + sourceObject); + + inverseRelationship = [relationship inverseRelationship]; + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"inverseRelationship=%@", + inverseRelationship); + + if (!inverseRelationship) + { + NSEmitTODO(); + //[self notImplemented: _cmd]; //TODO if !inverseRelationship + inverseRelationship = [relationship hiddenInverseRelationship]; + //VERIFY (don't know if this is the good way) + } + + invRelEntity = [inverseRelationship entity]; + invRelEntityClassProperties = [invRelEntity classProperties]; + invRelName = [inverseRelationship name]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"invRelName=%@", + invRelName); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"sourceObject=%@", + sourceObject); + + qualifier = [EOKeyValueQualifier qualifierWithKey: invRelName + operatorSelector: @selector(isEqualTo:) + value: sourceObject]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"qualifier=%@", qualifier); + + fetchSpec = [EOFetchSpecification fetchSpecification]; + + [fetchSpec setQualifier: qualifier]; + [fetchSpec setEntityName: [destinationEntity name]]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"fetchSpec=%@", fetchSpec); + + objects = [context objectsWithFetchSpecification: fetchSpec + editingContext: context]; + + [self _registerSnapshot: objects + forSourceGlobalID: globalID + relationshipName: name + editingContext: context];//OK + } + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"objects=%@", objects); + EOFLOGObjectFnStop(); + + return objects; +} + +- (void)_registerSnapshot: (NSArray*)snapshot + forSourceGlobalID: (EOGlobalID*)globalID + relationshipName: (NSString*)name + editingContext: (EOEditingContext*)context +{ + //OK + NSArray *gids; + + EOFLOGObjectFnStart(); + + gids = [context resultsOfPerformingSelector: @selector(globalIDForObject:) + withEachObjectInArray: snapshot]; + + [_database recordSnapshot: gids + forSourceGlobalID: globalID + relationshipName: name]; + + EOFLOGObjectFnStop(); +} + +- (void)refaultObject: object + withGlobalID: (EOGlobalID *)globalID + editingContext: (EOEditingContext *)context +{ + EOFLOGObjectFnStart(); + + [EOObserverCenter suppressObserverNotification]; + + NS_DURING + { + [object clearProperties];//OK + } + NS_HANDLER + { + [EOObserverCenter enableObserverNotification]; + + NSLog(@"EXCEPTION %@", localException); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"EXCEPTION %@", + localException); + + [localException raise]; + } + NS_ENDHANDLER; + + [EOObserverCenter enableObserverNotification]; + + if ([(EOKeyGlobalID *)globalID areKeysAllNulls]) + NSWarnLog(@"All key of globalID %p (%@) are nulls", + globalID, + globalID); + + [self _turnToFault: object + gid: globalID + editingContext: context + isComplete: YES]; //Why YES ? + + //NO: done in edcontext by calling clearOriginalSnapshotForObject: [self forgetSnapshotForGlobalID:globalID]; + + EOFLOGObjectFnStop(); +} + +- (void)saveChangesInEditingContext: (EOEditingContext *)context +{ + //TODO: locks ? + NSException *exception = nil; + + EOFLOGObjectFnStart(); + + [self prepareForSaveWithCoordinator: nil + editingContext: context]; + + [self recordChangesInEditingContext]; + + NS_DURING + { + [self performChanges]; + } + NS_HANDLER + { + NSDebugMLog(@"EXCEPTION: %@", localException); + exception = localException; + } + NS_ENDHANDLER; + + //I don't know if this is really the good place to catch exception and rollback... + if (exception) + { + [self rollbackChanges]; + [exception raise]; + } + else + [self commitChanges]; + + EOFLOGObjectFnStop(); +} + +- (void)_fetchRelationship: (EORelationship *)relationship + withObjects: (NSArray *)objsArray + editingContext: (EOEditingContext *)context +{ + NSMutableArray *qualArray = nil; + NSEnumerator *objEnum = nil; + NSEnumerator *relEnum = nil; + NSDictionary *snapshot = nil; + id obj = nil; + id relObj = nil; + + EOFLOGObjectFnStart(); + + if ([objsArray count] > 0) + { + qualArray = [NSMutableArray arrayWithCapacity: 5]; + + if ([relationship isFlattened] == YES) + { + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"relationship %@ isFlattened", relationship); + + relEnum = [[relationship componentRelationships] objectEnumerator]; + + while ((relationship = [relEnum nextObject])) + { + // TODO rebuild object array for relationship path + + [self _fetchRelationship: relationship + withObjects: objsArray + editingContext: context]; + } + } + + objEnum = [objsArray objectEnumerator]; + while ((obj = [objEnum nextObject])) + { + relObj = [obj storedValueForKey: [relationship name]]; + snapshot = [self snapshotForGlobalID: + [context globalIDForObject: relObj]]; + + [qualArray addObject: [relationship + qualifierWithSourceRow: snapshot]]; + } + + [self objectsWithFetchSpecification: + [EOFetchSpecification + fetchSpecificationWithEntityName: + [[relationship destinationEntity] name] + qualifier: [EOAndQualifier qualifierWithQualifierArray: + qualArray] + sortOrderings: nil] + editingContext: context]; + } + + EOFLOGObjectFnStop(); +} + +- (NSArray *)objectsWithFetchSpecification: (EOFetchSpecification *)fetch + editingContext: (EOEditingContext *)context +{ // TODO + EODatabaseChannel *channel = nil; + NSMutableArray *array = nil; + NSDictionary *snapshot = nil; + NSString *entityName = nil; + EOEntity *entity = nil; + NSString *relationshipKeyPath = nil; + NSEnumerator *relationshipKeyPathEnum = nil; + NSMutableArray *qualArray = nil; + + /*NSEnumerator *subEntitiesEnum = nil; + EOEntity *subEntity = nil; + NSArray *subEntities = nil;*/ + NSArray* rawRowKeyPaths = nil; + BOOL usesDistinct = NO; + int num = 0; + int limit=0; + int i = 0; + id obj = nil; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"fetch=%@", fetch); + + if (_delegateRespondsTo.shouldFetchObjects == YES) + { + array = (id)[_delegate databaseContext: self + shouldFetchObjectsWithFetchSpecification: fetch + editingContext: context]; + } + + if (!array) + { + array = [NSMutableArray arrayWithCapacity: 8]; + + entityName = [fetch entityName];//OK + entity = [_database entityNamed: entityName];//OK + NSAssert1(entity,@"No entity named %@", + entityName); + + /* moved in EODatabaseChannel _selectWithFetchSpecification:(EOFetchSpecification *)fetch + editingContext:(EOEditingContext *)context + + limit = [fetch fetchLimit]; + usesDistinct = [fetch usesDistinct]; + + + subEntities = [entity subEntities]; + + if ([subEntities count] && [fetch isDeep] == YES) + { + subEntitiesEnum = [subEntities objectEnumerator]; + while ((subEntity = [subEntitiesEnum nextObject])) + { + EOFetchSpecification *fetchSubEntity; + + fetchSubEntity = [[fetch copy] autorelease]; + [fetchSubEntity setEntityName:[entity name]]; + + [array addObjectsFromArray:[context objectsWithFetchSpecification: + fetchSubEntity]]; + } + } + */ + rawRowKeyPaths = [fetch rawRowKeyPaths];//OK + if (rawRowKeyPaths) + { + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + } + + if ([entity cachesObjects] == YES)//OK + { + ///TODO MG!!! + NSMutableArray *cache; + NSEnumerator *cacheEnum; + EOQualifier *qualifier; + EOGlobalID *gid; + BOOL isFault; + + qualifier = [fetch qualifier]; + + cache = (id)[_database resultCacheForEntityNamed: entityName]; + if (cache == nil) + { + NSMutableDictionary *row = nil; + EOAdaptorChannel *adaptorChannel = nil; + + channel = [self availableChannel]; + adaptorChannel = [channel adaptorChannel]; + + if (_flags.beganTransaction == NO + && _updateStrategy == EOUpdateWithPessimisticLocking) + { + [_adaptorContext beginTransaction]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"BEGAN TRANSACTION FLAG==>YES"); + + _flags.beganTransaction = YES; + } + + [adaptorChannel selectAttributes: [entity attributesToFetch] + fetchSpecification: + [EOFetchSpecification + fetchSpecificationWithEntityName: entityName + qualifier: nil + sortOrderings: nil] + lock: NO + entity: entity]; + + cache = [NSMutableArray arrayWithCapacity: 16]; + + while ((row = [adaptorChannel fetchRowWithZone: NULL])) + { + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"row=%@", row); + + gid = [entity globalIDForRow: row]; + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"gid=%@", gid); + + [_database recordSnapshot: row + forGlobalID: gid]; + [cache addObject: gid]; + } + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"Finished fetch"); + [channel cancelFetch]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"setResultCache"); + [_database setResultCache: cache + forEntityNamed: entityName]; + } + + cacheEnum = [cache objectEnumerator]; + while ((gid = [cacheEnum nextObject])) + { + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"gid=%@", gid); + + snapshot = [self snapshotForGlobalID: gid]; + if (snapshot) + { + if (!qualifier + || [qualifier evaluateWithObject: snapshot] == YES) + { + obj = [context objectForGlobalID: gid]; + + isFault = [EOFault isFault: obj]; + + if (obj == nil || isFault == YES) + { + if (isFault == NO) + { + obj = [[entity classDescriptionForInstances] + createInstanceWithEditingContext: context + globalID: gid + zone: NULL]; + + NSAssert1(obj, @"No Object. [entity classDescriptionForInstances]=%@", [entity classDescriptionForInstances]); + [context recordObject: obj + globalID: gid]; + } + else + { + [self _removeBatchForGlobalID: + (EOKeyGlobalID *)gid + fault: obj]; + + [EOFault clearFault: obj]; + } + + [context initializeObject: obj + withGlobalID: gid + editingContext: context]; + + [obj awakeFromFetchInEditingContext: context]; + } + + if (usesDistinct == YES && num) + { + for (i = 0; i < num; i++) + { + if ([[array objectAtIndex: i] + isEqual: obj] == YES) + { + obj = nil; + break; + } + } + + if (obj == nil) + continue; + } + + [array addObject: obj]; + num++; + + if (limit && num >= limit) + { + if ([[context messageHandler] + editingContext: context + shouldContinueFetchingWithCurrentObjectCount: num + originalLimit: limit + objectStore: self] == YES) + limit = 0; + else + break; + } + } + } + } + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"array before sort: %@", + array); + + if ([fetch sortOrderings]) + array = (id)[array sortedArrayUsingKeyOrderArray: + [fetch sortOrderings]]; + } + else + { +//cachesObject +//fetchspe isDeep ret 1 + channel = [self _obtainOpenChannel]; + + if (!channel) + { + NSEmitTODO(); + [self notImplemented: _cmd];//TODO + } + else + { + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"channel class %@ [channel isFetchInProgress]=%s", + [channel class], + ([channel isFetchInProgress] ? "YES" : "NO")); + + NSLog(@"%@ -- %@ 0x%x: channel isFetchInProgress=%s", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + ([channel isFetchInProgress] ? "YES" : "NO")); + + //mirko: + if (_flags.beganTransaction == NO + && _updateStrategy == EOUpdateWithPessimisticLocking) + { + [_adaptorContext beginTransaction]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"BEGAN TRANSACTION FLAG==>YES"); + _flags.beganTransaction = YES; + } + + if ([entity isAbstractEntity] == NO) //Mirko ??? + { + int autoreleaseSteps = 20; + int autoreleaseStep = autoreleaseSteps; + BOOL promptsAfterFetchLimit = NO; + NSAutoreleasePool *arp = nil;//To avoid too much memory use when fetching a lot of objects + int limit = 0; + + [channel selectObjectsWithFetchSpecification: fetch + editingContext: context];//OK + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"[channel isFetchInProgress]=%s", + ([channel isFetchInProgress] ? "YES" : "NO")); + + limit = [fetch fetchLimit];//OK + promptsAfterFetchLimit = [fetch promptsAfterFetchLimit]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"Will Fetch"); + + NS_DURING + { + arp = [NSAutoreleasePool new]; + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"[channel isFetchInProgress]=%s", + ([channel isFetchInProgress] ? "YES" : "NO")); + + while ((obj = [channel fetchObject])) + { + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"fetched an object"); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"FETCH OBJECT object=%@\n\n", + obj); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"%d usesDistinct: %s", + num, + (usesDistinct ? "YES" : "NO")); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"object=%@\n\n", obj); + + if (usesDistinct == YES && num) + { + for (i = 0; i < num; i++) + { + if ([[array objectAtIndex: i] + isEqual :obj] == YES) + { + obj = nil; + break; + } + } + + if (obj == nil) + continue; + } + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"AFTER FETCH"); + [array addObject: obj]; + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"array count=%d", + [array count]); + num++; + + if (limit > 0 && num >= limit) + { + if ([[context messageHandler] + editingContext: context + shouldContinueFetchingWithCurrentObjectCount: num + originalLimit: limit + objectStore: self] == YES) + limit = 0;//?? + else + break; + } + + if (autoreleaseStep <= 0) + { + DESTROY(arp); + autoreleaseStep = autoreleaseSteps; + arp = [NSAutoreleasePool new]; + } + else + autoreleaseStep--; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"WILL FETCH NEXT OBJECT"); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"[channel isFetchInProgress]=%s", + ([channel isFetchInProgress] ? "YES" : "NO")); + } + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"finished fetch"); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"array=%@", array); + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"step 0 channel is busy=%d", + (int)[channel isFetchInProgress]); + + [channel cancelFetch]; //OK + + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"step 1 channel is busy=%d", + (int)[channel isFetchInProgress]); + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"array=%@", + array); + + //TODO + /* + handle exceptio in fetchObject + channel fetchObject + + if eception: + if ([editcontext handleError:localException]) + { + //TODO + } + else + { + //TODO + }; + */ + } + NS_HANDLER + { + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"AN EXCEPTION: %@", + localException); + + [localException retain]; + DESTROY(arp); + [localException autorelease]; + [localException raise]; + } + NS_ENDHANDLER; + } + } + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"step 2 channel is busy=%d", + (int)[channel isFetchInProgress]); + } + + //VERIFY + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"array before prefetchingRelationshipKeyPaths: %@", + array); + + if ([fetch prefetchingRelationshipKeyPaths]) //OK + qualArray = [NSMutableArray arrayWithCapacity: 5]; + + relationshipKeyPathEnum = [[fetch prefetchingRelationshipKeyPaths] + objectEnumerator]; + + while ((relationshipKeyPath = [relationshipKeyPathEnum nextObject])) + { + NSArray *relationshipKeyArray = [relationshipKeyPath + componentsSeparatedByString: @"."]; + NSEnumerator *relationshipKeyEnum; + EORelationship *relationship; + EOEntity *currentEntity = entity; + NSString *relationshipKey; + + relationshipKeyEnum = [relationshipKeyArray objectEnumerator]; + while ((relationshipKey = [relationshipKeyEnum nextObject])) + { + relationship = [currentEntity relationshipNamed: relationshipKey]; + currentEntity = [relationship destinationEntity]; + + // TODO rebuild object array for relationship path + + [self _fetchRelationship: relationship + withObjects: array + editingContext: context]; + } + } + + if (_delegateRespondsTo.didFetchObjects == YES) + [_delegate databaseContext: self + didFetchObjects: array + fetchSpecification: fetch + editingContext: context]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"step 1 channel is busy=%d", + (int)[channel isFetchInProgress]); + } + + //EOFLOGObjectLevelArgs(@"EODatabaseContext", @"array: %@", array); + EOFLOGObjectFnStop(); + + return array; +} + +- (BOOL)isObjectLockedWithGlobalID: (EOGlobalID *)gid + editingContext: (EOEditingContext *)context +{ + return [self isObjectLockedWithGlobalID: gid]; +} + +- (void)lockObjectWithGlobalID: (EOGlobalID *)globalID + editingContext: (EOEditingContext *)context +{ // TODO + EOKeyGlobalID *gid = (EOKeyGlobalID *)globalID; + EODatabaseChannel *channel; + EOEntity *entity; + NSArray *attrsUsedForLocking, *primaryKeyAttributes; + NSDictionary *snapshot; + NSMutableDictionary *qualifierSnapshot, *lockSnapshot; + NSMutableArray *lockAttributes; + NSEnumerator *attrsEnum; + EOQualifier *qualifier; + EOAttribute *attribute; + + if ([self isObjectLockedWithGlobalID: gid] == NO) + { + snapshot = [self snapshotForGlobalID: gid]; + + if (_delegateRespondsTo.shouldLockObject == YES && + [_delegate databaseContext: self + shouldLockObjectWithGlobalID: gid + snapshot: snapshot] == NO) + return; + + channel = [self availableChannel]; + entity = [_database entityNamed: [gid entityName]]; + + NSAssert1(entity, @"No entity named %@", + [gid entityName]); + + attrsUsedForLocking = [entity attributesUsedForLocking]; + primaryKeyAttributes = [entity primaryKeyAttributes]; + + qualifierSnapshot = [NSMutableDictionary dictionaryWithCapacity: 16]; + lockSnapshot = [NSMutableDictionary dictionaryWithCapacity: 8]; + lockAttributes = [NSMutableArray arrayWithCapacity: 8]; + + attrsEnum = [primaryKeyAttributes objectEnumerator]; + while ((attribute = [attrsEnum nextObject])) + { + NSString *name = [attribute name]; + + [lockSnapshot setObject: [snapshot objectForKey:name] + forKey: name]; + } + + attrsEnum = [attrsUsedForLocking objectEnumerator]; + while ((attribute = [attrsEnum nextObject])) + { + NSString *name = [attribute name]; + + if ([primaryKeyAttributes containsObject:attribute] == NO) + { + if ([attribute adaptorValueType] == EOAdaptorBytesType) + { + [lockAttributes addObject: attribute]; + [lockSnapshot setObject: [snapshot objectForKey:name] + forKey: name]; + } + else + [qualifierSnapshot setObject: [snapshot objectForKey:name] + forKey: name]; + } + } + + // Turbocat + if ([[qualifierSnapshot allKeys] count] > 0) + qualifier = [EOAndQualifier + qualifierWithQualifiers: + [entity qualifierForPrimaryKey: + [entity primaryKeyForGlobalID: gid]], + [EOQualifier qualifierToMatchAllValues: + qualifierSnapshot], + nil]; + + if ([lockAttributes count] == 0) + lockAttributes = nil; + if ([lockSnapshot count] == 0) + lockSnapshot = nil; + + if (_flags.beganTransaction == NO) + { + [[[channel adaptorChannel] adaptorContext] beginTransaction]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"BEGAN TRANSACTION FLAG==>YES"); + + _flags.beganTransaction = YES; + } + + NS_DURING + [[channel adaptorChannel] lockRowComparingAttributes: lockAttributes + entity: entity + qualifier: qualifier + snapshot: lockSnapshot]; + NS_HANDLER + { + if (_delegateRespondsTo.shouldRaiseForLockFailure == YES) + { + if ([_delegate databaseContext: self + shouldRaiseExceptionForLockFailure:localException] + == YES) + [localException raise]; + } + else + [localException raise]; + } + NS_ENDHANDLER; + + [self registerLockedObjectWithGlobalID: gid]; + } +} + +- (void)invalidateAllObjects +{ + [self invalidateObjectsWithGlobalIDs: [[_database snapshot] allKeys]]; + + [[NSNotificationCenter defaultCenter] + postNotificationName: EOInvalidatedAllObjectsInStoreNotification + object: self]; +} + +- (void)invalidateObjectsWithGlobalIDs: (NSArray *)globalIDs +{ + NSMutableArray *array = nil; + NSEnumerator *enumerator; + EOKeyGlobalID *gid; + + if (_delegateRespondsTo.shouldInvalidateObject == YES) + { + array = [NSMutableArray array]; + enumerator = [globalIDs objectEnumerator]; + + while ((gid = [enumerator nextObject])) + { + if ([_delegate databaseContext: self + shouldInvalidateObjectWithGlobalID: gid + snapshot: [self snapshotForGlobalID: gid]] == YES) + [array addObject: gid]; + } + } + + [_database forgetSnapshotsForGlobalIDs: ((id)array ? (id)array : globalIDs)]; +} + +@end + + +@implementation EODatabaseContext(EOCooperatingObjectStoreSupport) + +- (BOOL)ownsGlobalID: (EOGlobalID *)globalID +{ + if ([globalID isKindOfClass: [EOKeyGlobalID class]] && + [_database entityNamed: [globalID entityName]]) + return YES; + + return NO; +} + +- (BOOL)ownsObject: (id)object +{ + if ([_database entityForObject: object]) + return YES; + + return NO; +} + +- (BOOL)ownsEntityNamed: (NSString *)entityName +{ + if ([_database entityNamed: entityName]) + return YES; + + return NO; +} + +- (BOOL)handlesFetchSpecification: (EOFetchSpecification *)fetchSpecification +{ + //OK + if ([_database entityNamed: [fetchSpecification entityName]]) + return YES; + else + return NO; +} +/*//Mirko: +- (EODatabaseOperation *)_dbOperationWithObject:object + operator:(EODatabaseOperator)operator +{ + NSMapEnumerator gidEnum; + EODatabaseOperation *op; + EOGlobalID *gid; + + gidEnum = NSEnumerateMapTable(_dbOperationsByGlobalID); + while (NSNextMapEnumeratorPair(&gidEnum, (void **)&gid, (void **)&op)) + { + if ([[op object] isEqual:object] == YES) + { + if ([op databaseOperator] == operator) + return op; + + return nil; + } + } + + return nil; +} + +- (void)_setGlobalID:(EOGlobalID *)globalID +forDatabaseOperation:(EODatabaseOperation *)op +{ + EOGlobalID *oldGlobalID = [op globalID]; + + [op _setGlobalID:globalID]; + + NSMapInsert(_dbOperationsByGlobalID, globalID, op); + NSMapRemove(_dbOperationsByGlobalID, oldGlobalID); +} + +- (EODatabaseOperation *)_dbOperationWithGlobalID:(EOGlobalID *)globalID + object:object + entity:(EOEntity *)entity + operator:(EODatabaseOperator)operator +{ + EODatabaseOperation *op; + NSMutableDictionary *newRow; + NSMapEnumerator gidEnum; + EOAttribute *attribute; + EOGlobalID *gid; + NSString *key; + NSArray *classProperties; + EONull *null = [EONull null]; + BOOL found = NO; + int i, count; + id val; + + gidEnum = NSEnumerateMapTable(_dbOperationsByGlobalID); + while (NSNextMapEnumeratorPair(&gidEnum, (void **)&gid, (void **)&op)) + { + if ([[op object] isEqual:object] == YES) + { + found = YES; + break; + } + } + + if (found == YES) + return op; + + if (globalID == nil) + globalID = [[[EOTemporaryGlobalID alloc] init] autorelease]; + + op = [[[EODatabaseOperation alloc] initWithGlobalID:globalID + object:object + entity:entity] autorelease]; + + [op setDatabaseOperator:operator]; + [op setDBSnapshot:[self snapshotForGlobalID:globalID]]; + + newRow = [op newRow]; + + classProperties = [entity classProperties]; + + count = [classProperties count]; + for (i = 0; i < count; i++) + { + attribute = [classProperties objectAtIndex:i]; + if ([attribute isKindOfClass:[EOAttribute class]] == NO) + continue; + + key = [attribute name]; + + if ([attribute isFlattened] == NO) + { + val = [object storedValueForKey:key]; + + if (val == nil) + val = null; + + [newRow setObject:val forKey:key]; + } + } + + NSLog(@"** %@ # %@", globalID, [op dbSnapshot]); + NSLog(@"-- %@", [op newRow]); + + NSMapInsert(_dbOperationsByGlobalID, globalID, op); + + return op; +} + +*/ + +// Prepares to save changes. Obtains primary keys for any inserted objects +// in the EditingContext that are owned by this context. +- (void)prepareForSaveWithCoordinator: (EOObjectStoreCoordinator *)coordinator + editingContext: (EOEditingContext *)context +{ + //near OK + NSArray *insertedObjects = nil; + int i = 0; + int count = 0; + + EOFLOGObjectFnStart(); + NSAssert(context, @"No editing context"); + + _flags.preparingForSave = YES; + _coordinator=coordinator;//RETAIN ? + _editingContext=context;//RETAIN ? + + // First, create dbOperation map if there's none + if (!_dbOperationsByGlobalID) + _dbOperationsByGlobalID = NSCreateMapTable(NSObjectMapKeyCallBacks, + NSObjectMapValueCallBacks, + 32); + + // Next, build list of Entity which need PK generator + [self _buildPrimaryKeyGeneratorListForEditingContext: context]; + + // Now get newly inserted objects + // For each objet, we will recordInsertForObject: and relay PK if it is !nil + insertedObjects = [context insertedObjects]; + i = 0; + count = [insertedObjects count]; + + for (i = 0; i < count; i++) + { + id object = [insertedObjects objectAtIndex: i]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"object=%p",object); + + if ([self ownsObject:object]) + { + NSDictionary *objectPK = nil; + EODatabaseOperation *dbOpe = nil; + NSMutableDictionary *newRow = nil; + EOEntity *entity = [_database entityForObject:object]; + + [self recordInsertForObject: object]; + objectPK = [self _primaryKeyForObject: object]; + + if (objectPK) + { + dbOpe = [self databaseOperationForObject: object]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"object=%p dbOpe=%@", + object,dbOpe); + + newRow=[dbOpe newRow]; + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"newRow=%@", newRow); + + [self relayPrimaryKey: objectPK + object: object + entity: entity]; + } + } + } + + EOFLOGObjectFnStop(); +} + + +- (void)recordChangesInEditingContext +{ + int which = 0; + NSArray *objects[3] = {nil, nil, nil}; + + EOFLOGObjectFnStart(); + + [self _assertValidStateWithSelector: + @selector(recordChangesInEditingContext)]; + + NSAssert(_editingContext, @"No editing context"); + // We'll examin object in the following order: + // insertedObjects, + // deletedObjects (because re-inserted object should be removed from deleteds) + // updatedObjects (because inserted/deleted objects may cause some other objects to be updated). + + for (which = 0; which < 3; which++) + { + int i, count; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"Unprocessed: %@", + [_editingContext unprocessedDescription]); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"Objects: %@", + [_editingContext objectsDescription]); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"which=%d", which); + + if (which == 0) + objects[which] = [_editingContext insertedObjects]; + else if (which == 1) + objects[which] = [_editingContext deletedObjects]; + else + objects[which] = [_editingContext updatedObjects]; + + count = [objects[which] count]; + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"objects[which]=%@", + objects[which]); + + // For each object + for (i = 0; i < count; i++) + { + NSDictionary *currentCommittedSnapshot = nil; + NSArray *relationships = nil; + EODatabaseOperation *dbOpe = nil; + EOEntity *entity = nil; + id object = [objects[which] objectAtIndex: i]; + +//Mirko ?? if ([self ownsObject:object] == YES) + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"object %p (class=%@):\n%@", + object, + [object class], + object); + + entity = [_database entityForObject: object]; //OK for Update + + if (which == 0 || which == 2)//insert or update + { + NSDictionary *pk = nil; + NSDictionary *snapshot; + + [self recordUpdateForObject: object //Why ForUpdate ? Becuase PK already generated ? + changes: nil]; //OK for update + + // Get a dictionary of object properties+PK+relationships CURRENT values + snapshot = [object snapshot]; //OK for Update+Insert + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"snapshot %p: %@", + snapshot, snapshot); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"currentCommittedSnapshot %p: %@", + currentCommittedSnapshot, + currentCommittedSnapshot); + + // Get a dictionary of object properties+PK+relationships DATABASES values + if (!currentCommittedSnapshot) + currentCommittedSnapshot = + [self _currentCommittedSnapshotForObject:object]; //OK For Update + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"currentCommittedSnapshot %p: %@", + currentCommittedSnapshot, + currentCommittedSnapshot); + + //TODO so what ? + + // Get the PK + pk = [self _primaryKeyForObject: object];//OK for Update + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"pk=%@", pk); + + if (pk) + [self relayPrimaryKey: pk + object: object + entity: entity]; //OK for Update + } + + relationships = [entity relationships]; //OK for Update + + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"object=%p relationships: %@", + object,relationships); + + if (which == 1) //delete //Not in insert //not in update + { + int iRelationship = 0; + int relationshipsCount = [relationships count]; + + for (iRelationship = 0; iRelationship < relationshipsCount; + iRelationship++) + { + EORelationship *relationship = + [relationships objectAtIndex: iRelationship]; + + if ([relationship isToManyToOne]) + { + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + } + } + + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"object: %@", + object); + + [self recordDeleteForObject: object]; + } + + dbOpe = [self databaseOperationForObject: object]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"dbOpe=%@", dbOpe); + + if (which == 0 || which == 2) //insert or update + { +//En update: dbsnapshot +//en insert : snapshot ? en insert:dbsnap aussi + int iRelationship = 0; + int relationshipsCount = 0; + NSDictionary *snapshot = nil; + + if (which == 0) //Insert //see wotRelSaveChanes.1.log seems to use dbSna for insert ! + { + snapshot=[object snapshot];//NEW2 + //snapshot=[dbOpe dbSnapshot]; //NEW + + NSDebugMLog(@"[dbOpe dbSnapshot]=%@", [dbOpe dbSnapshot]); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"Insert: [dbOpe snapshot] %p=%@", + snapshot, snapshot); + } + else //Update + { + //NEWsnapshot=[dbOpe dbSnapshot]; + snapshot = [object snapshot]; + + //EOFLOGObjectLevelArgs(@"EODatabaseContext",@"Update: [dbOpe snapshot] %p=%@",snapshot,snapshot); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"Update: [object snapshot] %p=%@", + snapshot, snapshot); + } + + relationshipsCount = [relationships count]; + + for (iRelationship = 0; iRelationship < relationshipsCount; + iRelationship++) + { + NSArray *classProperties = nil; + EORelationship *relationship = nil; + EORelationship *substitutionRelationship = nil; + + relationship = [relationships objectAtIndex: iRelationship]; + +/* +get rel entity +entity model +model modelGroup +*/ + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"HANDLE relationship %@ for object %p (class=%@):\n%@", + [relationship name], + object, + [object class], + object); + NSDebugMLog(@"HANDLE relationship %@ for object %p (class=%@):\n%@", + [relationship name], + object, + [object class], + object); + + substitutionRelationship = + [relationship _substitutionRelationshipForRow: snapshot]; + + classProperties = [entity classProperties]; + +/* +rel name ==> toCountry + +rel isToMany (0) +nullifyAttributesInRelationship:rel sourceObject:object destinationObject:nil (snapshot objectForKey: rel name ) ? +*/ + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"relationship: %@", relationship); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"classProperties: %@", + classProperties); + + if ([classProperties indexOfObjectIdenticalTo: relationship] + != NSNotFound) //(or subst) + { + BOOL valuesAreEqual = NO; + BOOL isToMany = NO; + id relationshipCommitedSnapshotValue = nil; + NSString *relationshipName = [relationship name]; + id relationshipSnapshotValue; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"dbOpe=%@", + dbOpe); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"which=%d", + which); + //EOFLOGObjectLevelArgs(@"EODatabaseContext",@"OBJECT SNAPSHOT %p:\n%@\n\n",[object snapshot]); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"snapshot for object %p:\nsnapshot %p (count=%d)= \n%@\n\n", + object, snapshot, [snapshot count], + snapshot); + + // substitutionRelationship objectForKey: + relationshipSnapshotValue = + [snapshot objectForKey: relationshipName]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"relationshipSnapshotValue (snapshot %p rel name=%@): %@", + snapshot, + relationshipName, + relationshipSnapshotValue); + + if (which == 0) //Insert + currentCommittedSnapshot = [dbOpe dbSnapshot]; + else //Update + { + if (!currentCommittedSnapshot) + currentCommittedSnapshot = + [self _currentCommittedSnapshotForObject: object]; //OK For Update + } +//update: _commited +//insert: dbSn + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"currentCommittedSnapshot %p: %@", + currentCommittedSnapshot, + currentCommittedSnapshot); + + relationshipCommitedSnapshotValue = + [currentCommittedSnapshot objectForKey: + relationshipName]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"relationshipCommitedSnapshotValue (snapshot %p rel name=%@): %@", + currentCommittedSnapshot, + relationshipName, + relationshipCommitedSnapshotValue); + + isToMany = [relationship isToMany]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"isToMany: %s", + (isToMany ? "YES" : "NO")); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"relationshipSnapshotValue %p=%@", + relationshipSnapshotValue, + relationshipSnapshotValue); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"relationshipCommitedSnapshotValue %p=%@", + relationshipCommitedSnapshotValue, + relationshipCommitedSnapshotValue); + + if (relationshipSnapshotValue + == relationshipCommitedSnapshotValue) + valuesAreEqual = YES; + else if (isNilOrEONull(relationshipSnapshotValue)) + valuesAreEqual = isNilOrEONull(relationshipCommitedSnapshotValue); + else if (isToMany) + valuesAreEqual = [relationshipSnapshotValue + containsIdenticalObjectsWithArray: + relationshipCommitedSnapshotValue]; + else // ToOne bu not same object + valuesAreEqual = NO; + + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"object=%p valuesAreEqual: %s", + object,(valuesAreEqual ? "YES" : "NO")); + + if (valuesAreEqual) + { + //Equal Values ! + } + else + { + if (isToMany) + { + //relationshipSnapshotValue shallowCopy + // Old Values are removed values + NSArray *oldValues = [relationshipCommitedSnapshotValue arrayExcludingObjectsInArray: relationshipSnapshotValue]; + // Old Values are newly added values + NSArray *newValues = [relationshipSnapshotValue arrayExcludingObjectsInArray: relationshipCommitedSnapshotValue]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"oldValues count=%d", + [oldValues count]); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"oldValues=%@", + oldValues); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"newValues count=%d", + [newValues count]); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"newValues=%@", + newValues); + + // Record new values snapshots + if ([newValues count] > 0) + { + int newValuesCount = [newValues count]; + int iValue; + NSMutableArray *valuesGIDs = + [NSMutableArray array]; + + for (iValue = 0; + iValue < newValuesCount; + iValue++) + { + id aValue = [relationshipSnapshotValue + objectAtIndex: iValue]; + EOGlobalID *aValueGID = [self _globalIDForObject: aValue]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"YYYY valuesGIDs=%@", + valuesGIDs); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"YYYY aValueGID=%@", + aValueGID); + [valuesGIDs addObject:aValueGID]; + } + + [dbOpe recordToManySnapshot:valuesGIDs + relationshipName: relationshipName]; + } + + // Nullify removed object relation attributes + if ([oldValues count] > 0) + { + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"will call nullifyAttributes from source %p (class %@)", + object, [object class]); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"object %p=%@ (class=%@)", + object, object, + [object class]); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"relationshipName=%@", + relationshipName); + + [self nullifyAttributesInRelationship: + relationship + sourceObject: object + destinationObjects: oldValues]; + } + + // Relay relationship attributes in new objects + if ([newValues count] > 0) + { + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"will call relay from source %p (class %@)", + object, [object class]); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"object %p=%@ (class=%@)", + object, object, + [object class]); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"relationshipName=%@", + relationshipName); + + [self relayAttributesInRelationship: + relationship + sourceObject: object + destinationObjects: newValues]; + } + } + else + { + //id destinationObject=[object storedValueForKey:relationshipName]; + + if (relationshipCommitedSnapshotValue) // a value was removed + { + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"will call nullifyAttributes from source %p (class %@)", + object, [object class]); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"object %p=%@ (class=%@)", + object, object, + [object class]); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"relationshipName=%@", + relationshipName); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"destinationObject %p=%@ (class=%@)", + relationshipCommitedSnapshotValue, + relationshipCommitedSnapshotValue, + [relationshipCommitedSnapshotValue class]); + + [self nullifyAttributesInRelationship: + relationship + sourceObject: object + destinationObject: + relationshipCommitedSnapshotValue]; + } + + if (relationshipSnapshotValue) // a value was added + { + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"will call relay from source %p relname=%@", + object, + relationshipName); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"object %p=%@ (class=%@)", + object, object, + [object class]); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"relationshipName=%@", + relationshipName); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"destinationObject %p=%@ (class=%@)", + relationshipSnapshotValue, + relationshipSnapshotValue, + [relationshipSnapshotValue class]); + + [self relayAttributesInRelationship: + relationship + sourceObject: object + destinationObject: + relationshipSnapshotValue]; + } + } + } + } + else + { + //!toMany: + //dbSnapshot was empty + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"will call nullifyAttributesInRelationship on source %p relname=%@", + object, [relationship name]); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"object %p=%@ (class=%@)", + object, object, [object class]); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"relationshipName=%@", + [relationship name]); + + [self nullifyAttributesInRelationship: relationship + sourceObject: object /*CountryLabel*/ + destinationObjects: nil]; + } + +/* + NSMutableDictionary *row; + NSMutableArray *toManySnapshot, *newToManySnapshot; + NSArray *joins = [(EORelationship *)property joins]; + NSString *joinName; + EOJoin *join; + int h, count; + id value; + + name = [(EORelationship *)property name]; + row = [NSMutableDictionary dictionaryWithCapacity:4]; + count = [joins count]; + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"rel name=%@", name); + + if ([property isToMany] == YES) + { + NSMutableArray *toManyGIDArray; + NSArray *toManyObjects; + EOGlobalID *toManyGID; + id toManyObj; + + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"rel 1 sourceGID=%@", gid); + toManySnapshot = [[[self snapshotForSourceGlobalID:gid + relationshipName:name] + mutableCopy] autorelease]; + if (toManySnapshot == nil) + toManySnapshot = [NSMutableArray array]; + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"rel 1", name); + + newToManySnapshot = [NSMutableArray + arrayWithCapacity:10]; + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"rel 1", name); + + toManyObjects = [object storedValueForKey:name]; + toManyGIDArray = [NSMutableArray + arrayWithCapacity: + [toManyObjects count]]; + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"rel 1", name); + + enumerator = [toManyObjects objectEnumerator]; + while ((toManyObj = [enumerator nextObject])) + { + toManyGID = [_editingContext globalIDForObject: + toManyObj]; + + [toManyGIDArray addObject:toManyGID]; + + + if ([toManySnapshot containsObject:toManyGID] == NO) + { + [newToManySnapshot addObject:toManyGID]; + + for (h=0; h 0) + { + EOAdaptorChannel *adaptorChannel = nil; + EODatabaseChannel *dbChannel = [self _obtainOpenChannel]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"self=%p preparingForSave=%d beganTransaction=%d", + self, + (int)_flags.preparingForSave, + (int)_flags.beganTransaction); + + if (_flags.beganTransaction == NO)//MIRKO + { + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"self=%p [_adaptorContext transactionNestingLevel]=%d", + self, + (int)[_adaptorContext transactionNestingLevel]); + + if ([_adaptorContext transactionNestingLevel] == 0) //?? + [_adaptorContext beginTransaction]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"BEGAN TRANSACTION FLAG==>YES"); + + _flags.beganTransaction = YES; + } + + adaptorChannel = [dbChannel adaptorChannel]; + + if (_delegateRespondsTo.willPerformAdaptorOperations == YES) + orderedAdaptorOperations = [_delegate databaseContext: self + willPerformAdaptorOperations: + orderedAdaptorOperations + adaptorChannel: adaptorChannel]; + NS_DURING + { + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"performAdaptorOperations:"); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"self=%p preparingForSave=%d beganTransaction=%d", + self, + (int)_flags.preparingForSave, + (int)_flags.beganTransaction); + + [adaptorChannel performAdaptorOperations: orderedAdaptorOperations]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"self=%p preparingForSave=%d beganTransaction=%d", + self, + (int)_flags.preparingForSave, + (int)_flags.beganTransaction); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"after performAdaptorOperations:"); + } + NS_HANDLER + { + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"Exception in performAdaptorOperations:%@", + localException); + [localException raise]; + //MIRKO + //TODO + /* + NSException *exp; + NSMutableDictionary *userInfo; + EOAdaptorOperation *adaptorOp; + + userInfo = [NSMutableDictionary dictionaryWithCapacity:10]; + [userInfo addEntriesFromDictionary:[localException userInfo]]; + [userInfo setObject:self forKey:EODatabaseContextKey]; + [userInfo setObject:dbOps + forKey:EODatabaseOperationsKey]; + + adaptorOp = [userInfo objectForKey:EOFailedAdaptorOperationKey]; + + dbEnum = [dbOps objectEnumerator]; + while ((op = [dbEnum nextObject])) + if ([[op adaptorOperations] containsObject:adaptorOp] == YES) + { + [userInfo setObject:op + forKey:EOFailedDatabaseOperationKey]; + break; + } + + exp = [NSException exceptionWithName:EOGeneralDatabaseException + reason:[NSString stringWithFormat: + @"%@ -- %@ 0x%x: failed with exception name:%@ reason:\"%@\"", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, [localException name], + [localException reason]] + userInfo:userInfo]; + + [exp raise]; + */ + } + NS_ENDHANDLER; + +//This is not done by mirko: + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"self=%p preparingForSave=%d beganTransaction=%d", + self, + (int)_flags.preparingForSave, + (int)_flags.beganTransaction); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"self=%p _uniqueStack %p=%@", + self, _uniqueStack, _uniqueStack); + + dbOpeEnum = NSEnumerateMapTable(_dbOperationsByGlobalID); + + while (NSNextMapEnumeratorPair(&dbOpeEnum, (void **)&gid, + (void **)&dbOpe)) + { + EODatabaseOperator databaseOperator = EODatabaseNothingOperator; + + //call dbOpe adaptorOperations ? + if ([dbOpe databaseOperator] == EODatabaseNothingOperator) + { + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"Db Ope %@ for Nothing !!!", dbOpe); + } + else + { + EOEntity *entity = nil; + NSArray *dbSnapshotKeys = nil; + NSMutableDictionary *newRow = nil; + NSDictionary *values = nil; + id object = nil; + NSArray *adaptorOpe = nil; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"dbOpe=%@", dbOpe); + + object = [dbOpe object]; + adaptorOpe = [dbOpe adaptorOperations]; + databaseOperator = [dbOpe databaseOperator]; + entity = [dbOpe entity]; + dbSnapshotKeys = [entity dbSnapshotKeys]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"dbSnapshotKeys=%@", + dbSnapshotKeys); + + newRow = [dbOpe newRow]; + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"newRow=%@", + newRow); + + values = [newRow valuesForKeys: dbSnapshotKeys]; + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"RECORDSNAPSHOT values=%@", values); + //if update: forgetSnapshotForGlobalID: + + [self recordSnapshot: values + forGlobalID: gid]; + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"self=%p _uniqueStack %p=%@", + self, _uniqueStack, _uniqueStack); + + if (databaseOperator == EODatabaseUpdateOperator) //OK for update //Do it forInsert too //TODO + { + NSDictionary *toManySnapshots = [dbOpe toManySnapshots]; + + if (toManySnapshots) + { + NSDebugMLog(@"toManySnapshots=%@", toManySnapshots); + NSEmitTODO(); + + //TODONOW [self notImplemented: _cmd]; //TODO + } + } + } + } + } + + EOFLOGObjectFnStop(); +} + +- (void)commitChanges +{ + BOOL doIt = NO; + NSMutableArray *deletedObjects = [NSMutableArray array]; + NSMutableArray *insertedObjects = [NSMutableArray array]; + NSMutableArray *updatedObjects = [NSMutableArray array]; + NSMutableDictionary *gidChangedUserInfo = nil; + + EOFLOGObjectFnStart(); + [self _assertValidStateWithSelector: @selector(commitChanges)]; + + //REVOIR: don't do it if no adaptor ope + { + NSMapEnumerator dbOpeEnum; + EOGlobalID *gid = nil; + EODatabaseOperation *dbOpe = nil; + dbOpeEnum = NSEnumerateMapTable(_dbOperationsByGlobalID); + + while (!doIt && NSNextMapEnumeratorPair(&dbOpeEnum, (void **)&gid, + (void **)&dbOpe)) + { + doIt = ([dbOpe adaptorOperations] != nil); + } + } + + if (doIt) + { + if (_flags.beganTransaction != YES)//it is not set here in WO + { + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + } + else if ([_adaptorContext transactionNestingLevel] == 0) + { + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + } + else + { + NSMapEnumerator dbOpeEnum; + EOGlobalID *gid = nil; + EODatabaseOperation *dbOpe = nil; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"BEGAN TRANSACTION FLAG==>NO"); + + _flags.beganTransaction = NO; + [_adaptorContext commitTransaction]; //adaptorcontext transactionDidCommit + + dbOpeEnum = NSEnumerateMapTable(_dbOperationsByGlobalID); + while (NSNextMapEnumeratorPair(&dbOpeEnum, (void **)&gid, + (void **)&dbOpe)) + { + EODatabaseOperator databaseOperator = EODatabaseNothingOperator; + EOGlobalID *dbOpeGID = nil; + EOGlobalID *newGID = nil; + EOEntity *entity = nil; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"dbOpe=%@", dbOpe); + + [EOObserverCenter suppressObserverNotification]; + + NS_DURING + { + databaseOperator = [dbOpe databaseOperator]; + entity = [dbOpe entity]; + + if (databaseOperator == EODatabaseInsertOperator + || databaseOperator == EODatabaseUpdateOperator)//OK for update + { + id object = nil; + NSDictionary *newRowValues = nil; + //gid isTemporary + NSDictionary *primaryKeyDiffs = [dbOpe primaryKeyDiffs];//OK for update + + if (primaryKeyDiffs) + { + NSEmitTODO(); + NSLog(@"primaryKeyDiffs=%@", primaryKeyDiffs); + [self notImplemented: _cmd]; //TODO: if primaryKeyDiffs + } + + if (databaseOperator == EODatabaseInsertOperator) + { + NSArray *classPropertyAttributeNames = + [entity classPropertyAttributeNames]; + NSDictionary *newRow = [dbOpe newRow]; + + newRowValues = [newRow valuesForKeys: + classPropertyAttributeNames]; + + //TODO REVOIR !! + newGID = [entity globalIDForRow: newRow + isFinal: YES]; + } + else + { + NSArray *classPropertyAttributes = [entity _classPropertyAttributes];//OK for update + + newRowValues = [dbOpe rowDiffsForAttributes: classPropertyAttributes];//OK for update + } + + object = [dbOpe object];//OK for update + [object takeStoredValuesFromDictionary: newRowValues];//OK for update + + /*mirko instead: + [object takeStoredValuesFromDictionary: + [op rowDiffsForAttributes:attributes]]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"-_+ %@ # %@", gid, object); + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"-_* %@", [op newRow]); + [_database recordSnapshot:[op newRow] + forGlobalID:gid]; + + toManySnapshots = [op toManySnapshots]; + toManyEnum = [toManySnapshots keyEnumerator]; + while ((key = [toManyEnum nextObject])) + [_database recordSnapshot:[toManySnapshots objectForKey:key] + forSourceGlobalID:gid + relationshipName:key]; + */ + } + } + NS_HANDLER + { + [EOObserverCenter enableObserverNotification]; + + NSLog(@"EXCEPTION %@", localException); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"EXCEPTION %@", + localException); + + [localException raise]; + } + NS_ENDHANDLER; + + [EOObserverCenter enableObserverNotification]; + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"dbOpe=%@", dbOpe); + + dbOpeGID = [dbOpe globalID]; //OK for update + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"dbOpeGID=%@", + dbOpeGID); + + switch (databaseOperator) + { + case EODatabaseInsertOperator: + [insertedObjects addObject: dbOpeGID]; + + if (!gidChangedUserInfo) + gidChangedUserInfo = (NSMutableDictionary *) + [NSMutableDictionary dictionary]; + + [gidChangedUserInfo setObject: newGID + forKey: dbOpeGID]; //[_editingContext globalIDForObject:object]]; + break; + + case EODatabaseDeleteOperator: + [deletedObjects addObject: dbOpeGID]; + [_database forgetSnapshotForGlobalID: dbOpeGID]; //Mirko/?? + break; + + case EODatabaseUpdateOperator: + [updatedObjects addObject: dbOpeGID]; + break; + + case EODatabaseNothingOperator: + break; + } + } + } + } + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"call _cleanUpAfterSave"); + + [self _cleanUpAfterSave];//OK for update + + if (doIt) + { + //from mirko. seems ok + if (gidChangedUserInfo) + { + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"post EOGlobalIDChangedNotification"); + + [[NSNotificationCenter defaultCenter] + postNotificationName: EOGlobalIDChangedNotification + object: nil + userInfo: gidChangedUserInfo]; + } + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"post EOObjectsChangedInStoreNotification"); + + [[NSNotificationCenter defaultCenter] + postNotificationName: @"EOObjectsChangedInStoreNotification" + object: _database + userInfo: [NSDictionary dictionaryWithObjectsAndKeys: + deletedObjects, @"deleted", + insertedObjects, @"inserted", + updatedObjects, @"updated", + nil, nil]]; //call self _snapshotsChangedInDatabase: + } + + EOFLOGObjectFnStop(); +} + +- (void)rollbackChanges +{ // TODO +//adaptorcontext transactionNestingLevel +//if 0 ? _cleanUpAfterSave + EOFLOGObjectFnStart(); + + if (_flags.beganTransaction == YES) + { + [_adaptorContext rollbackTransaction]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"BEGAN TRANSACTION FLAG==>NO"); + + _flags.beganTransaction = NO; + + _numLocked = 0; + _lockedObjects = NSZoneRealloc(NULL, _lockedObjects, + _LOCK_BUFFER*sizeof(id)); + + NSResetMapTable(_dbOperationsByGlobalID); +/*//TODO + [_snapshots removeAllObjects]; + [_toManySnapshots removeAllObjects]; +*/ + } + + EOFLOGObjectFnStop(); +} + +- (NSDictionary *)valuesForKeys: (NSArray *)keys + object: (id)object +{ + //OK + EOEntity *entity; + EODatabaseOperation *dbOpe; + NSDictionary *newRow; + NSDictionary *values = nil; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"object=%p keys=%@", + object,keys); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"object=%p (class=%@)", + object, [object class]); + + //NSAssert(object, @"No object"); + + if (object) + { + entity = [_database entityForObject: object]; + + NSAssert1(entity, @"No entity for object %@", object); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"entity name=%@", + [entity name]); + + dbOpe = [self databaseOperationForObject: object]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"dbOpe=%p", dbOpe); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"dbOpe=%@", dbOpe); + + newRow = [dbOpe newRow]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"newRow=%p", newRow); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"newRow=%@", newRow); + + values = [newRow valuesForKeys: keys]; + } + else + { + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"No object"); + values = [NSDictionary dictionary]; + } + +// EOFLOGObjectLevelArgs(@"EODatabaseContext", @"values=%@", values); + + EOFLOGObjectFnStop(); + + return values; +} + +-(void)nullifyAttributesInRelationship: (EORelationship*)relationship + sourceObject: (id)sourceObject + destinationObject: (id)destinationObject +{ + EODatabaseOperation *sourceDBOpe = nil; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"relationship=%@", + relationship); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"sourceObject=%@", + sourceObject); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"destinationObject=%@", + destinationObject); + + if (destinationObject) + { + //Get SourceObject database operation + sourceDBOpe = [self databaseOperationForObject: sourceObject]; //TODO: useIt + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"sourceDBOpe=%@", + sourceDBOpe); + + if ([relationship isToManyToOne]) + { + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + } + else + { + // Key a dictionary of two array: destinationKeys and sourceKeys + NSDictionary *sourceToDestinationKeyMap = + [relationship _sourceToDestinationKeyMap]; //{destinationKeys = (customerCode); sourceKeys = (code); } + BOOL foreignKeyInDestination = [relationship foreignKeyInDestination]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"sourceToDestinationKeyMap=%@", + sourceToDestinationKeyMap); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"foreignKeyInDestination=%d", + foreignKeyInDestination); + + if (foreignKeyInDestination) + { + NSArray *destinationKeys = [sourceToDestinationKeyMap + objectForKey: @"destinationKeys"];//(customerCode) + int i, destinationKeysCount = [destinationKeys count]; + NSMutableDictionary *changes = [NSMutableDictionary dictionaryWithCapacity: destinationKeysCount]; + id null = [EONull null]; + + for (i = 0 ;i < destinationKeysCount; i++) + { + id destinationKey = [destinationKeys objectAtIndex: i]; + + [changes setObject: null + forKey: destinationKey]; + } + + [self recordUpdateForObject: destinationObject + changes: changes]; + } + else + { + //Do nothing ? + NSEmitTODO(); + //[self notImplemented: _cmd]; //TODO + } + } + } +} + +- (void)nullifyAttributesInRelationship: (EORelationship*)relationship + sourceObject: (id)sourceObject + destinationObjects: (NSArray*)destinationObjects +{ + int destinationObjectsCount = 0; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"relationship=%@", relationship); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"sourceObject=%@", sourceObject); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"destinationObjects=%@", destinationObjects); + + destinationObjectsCount = [destinationObjects count]; + + if (destinationObjectsCount > 0) + { + int i; + + for (i = 0; i < destinationObjectsCount; i++) + { + id object = [destinationObjects objectAtIndex: i]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"destinationObject %p=%@ (class %@)", + object, object, [object class]); + + [self nullifyAttributesInRelationship: relationship + sourceObject: sourceObject + destinationObject: object]; + } + } + + EOFLOGObjectFnStop(); +} + +-(void)relayAttributesInRelationship: (EORelationship*)relationship + sourceObject: (id)sourceObject + destinationObjects: (NSArray*)destinationObjects +{ + int destinationObjectsCount = 0; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"relationship=%@", relationship); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"sourceObject=%@", sourceObject); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"destinationObjects=%@", destinationObjects); + + destinationObjectsCount = [destinationObjects count]; + + if (destinationObjectsCount > 0) + { + int i; + + for (i = 0; i < destinationObjectsCount; i++) + { + id object = [destinationObjects objectAtIndex: i]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"destinationObject %p=%@ (class %@)", + object,object,[object class]); + + [self relayAttributesInRelationship: (EORelationship*)relationship + sourceObject: (id)sourceObject + destinationObject: object]; + } + } + + EOFLOGObjectFnStop(); +} + +- (NSDictionary*)relayAttributesInRelationship: (EORelationship*)relationship + sourceObject: (id)sourceObject + destinationObject: (id)destinationObject +{ + //OK + NSMutableDictionary *relayedValues = nil; + EODatabaseOperation *sourceDBOpe = nil; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"relationship=%@", + relationship); + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"sourceObject %p=%@ (class=%@)", + sourceObject,sourceObject,[sourceObject class]); + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"destinationObject %p=%@ (class=%@)", + destinationObject,destinationObject,[destinationObject class]); + + //Get SourceObject database operation + sourceDBOpe = [self databaseOperationForObject: sourceObject]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"sourceDBOpe=%@", sourceDBOpe); + + if ([sourceDBOpe databaseOperator] == EODatabaseNothingOperator) + { + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"Db Ope %@ for Nothing !!!", sourceDBOpe); + } + + if ([relationship isToManyToOne]) + { + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + } + else + { + // Key a dictionary of two array: destinationKeys and sourceKeys + NSDictionary *sourceToDestinationKeyMap = [relationship _sourceToDestinationKeyMap];//{destinationKeys = (customerCode); sourceKeys = (code); } + NSArray *destinationKeys = [sourceToDestinationKeyMap + objectForKey: @"destinationKeys"];//(customerCode) + NSArray *sourceKeys = [sourceToDestinationKeyMap + objectForKey: @"sourceKeys"];//(code) + NSMutableDictionary* sourceNewRow = [sourceDBOpe newRow];//OK in foreignKeyInDestination + BOOL foreignKeyInDestination = [relationship foreignKeyInDestination]; + int i, count; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"relationship=%@", + relationship); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"sourceToDestinationKeyMap=%@", + sourceToDestinationKeyMap); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"destinationKeys=%@", + destinationKeys); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"sourceKeys=%@", + sourceKeys); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"sourceNewRow=%@", + sourceNewRow); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"foreignKeyInDestination=%s", + (foreignKeyInDestination ? "YES" : "NO")); + + NSAssert([destinationKeys count] == [sourceKeys count], + @"destination keys count!=source keys count"); + + if (foreignKeyInDestination) + { + relayedValues = [[[sourceNewRow valuesForKeys: sourceKeys] + mutableCopy] autorelease];// {code = 0; } + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"relayedValues=%@", + relayedValues); + + count = [relayedValues count]; + + for (i = 0; i < count; i++) + { + id sourceKey = [sourceKeys objectAtIndex: i]; + id destKey = [destinationKeys objectAtIndex: i];//customerCode + id sourceValue = [relayedValues objectForKey: sourceKey]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"sourceKey=%@", + sourceKey); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"destKey=%@", + destKey); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"sourceValue=%@", + sourceValue); + + [relayedValues removeObjectForKey: sourceKey]; + [relayedValues setObject: sourceValue + forKey: destKey]; + } + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"relayedValues=%@", + relayedValues); + + [self recordUpdateForObject: destinationObject + changes: relayedValues]; + } + else + { + //Verify !! + NSDictionary *destinationValues; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"Call valuesForKeys destinationObject %p (class %@)", + destinationObject, [destinationObject class]); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"destinationKeys=%@", + destinationKeys); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"relationship=%@", + relationship); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"sourceKeys=%@", + sourceKeys); + + //Now take destinationKeys values + destinationValues = [self valuesForKeys: destinationKeys + object: destinationObject]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"destinationValues=%@", + destinationValues); + //And put these values for source keys in the return object (sourceValues) + + count = [destinationKeys count]; + relayedValues = (NSMutableDictionary*)[NSMutableDictionary dictionary]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"relayedValues=%@", + relayedValues); + + for (i = 0; i < count; i++) + { + id destinationKey = [destinationKeys objectAtIndex: i]; + id sourceKey = [sourceKeys objectAtIndex: i]; + id destinationValue = [destinationValues + objectForKey: destinationKey]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"destinationKey=%@", + destinationKey); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"sourceKey=%@", + sourceKey); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"destinationValue=%@", destinationValue); + + if (destinationValue)//?? or always + [relayedValues setObject: destinationValue + forKey: sourceKey]; + } + //Put these values in source object database ope new row + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"relayedValues=%@", + relayedValues); + + [sourceNewRow takeValuesFromDictionary: relayedValues]; + } + } + + if ([sourceDBOpe databaseOperator] == EODatabaseNothingOperator) + { + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"Db Ope %@ for Nothing !!!", sourceDBOpe); + } + + EOFLOGObjectFnStop(); + + return relayedValues; +//Mirko Code: +/* + NSMutableArray *keys; + NSDictionary *values; + EOGlobalID *relationshipGID; + id objectTo; + + objectTo = [object storedValueForKey:name]; + relationshipGID = [_editingContext + globalIDForObject:objectTo]; + if ([self ownsObject:objectTo] == YES) + { + for (h=0; h propagatesPrimaryKey=%s", + object, + [relationship name], + (propagatesPrimaryKey ? "YES" : "NO")); + + if (propagatesPrimaryKey) + { + NSString *relName = [substRelationship name]; //this one ?? + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"relName=%@", relName); + + if ([classPropertyNames containsObject: relName]) + { + id value = nil; + id snapshot = nil; + id snapshotValue = nil; + BOOL isToMany = NO; + + value = [object storedValueForKey: relName]; + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"value=%@", value); + + snapshot = [self _currentCommittedSnapshotForObject: object]; + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"snapshot=%@", + snapshot); + + snapshotValue = [snapshot objectForKey:relName];//ret nil + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"snapshotValue=%@", + snapshotValue); + + isToMany = [substRelationship isToMany]; //this one ?? + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"isToMany=%s", + (isToMany ? "YES" : "NO")); + + if (isToMany) + { + int valueValuesCount = 0; + int iValueValue = 0; + + value = [value shallowCopy]; + valueValuesCount = [value count]; + iValueValue = 0; + + for (iValueValue = 0; + iValueValue < valueValuesCount; + iValueValue++) + { + id valueValue = [value objectAtIndex: iValueValue]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"valueValue=%@", valueValue); + + [self relayPrimaryKey: pk + sourceObject: object + destObject: valueValue + relationship: substRelationship]; //this one ?? + } + } + else + { + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"value=%@", + value); + + [self relayPrimaryKey: pk + sourceObject: object + destObject: value + relationship: substRelationship]; //this one ?? + } + } + } + } + + EOFLOGObjectFnStop(); +} + +- (void) createAdaptorOperationsForDatabaseOperation: (EODatabaseOperation*)dbOpe + attributes: (NSArray*)attributes +{ + //NEAR OK + BOOL isSomethingTodo = YES; + EOEntity *entity = nil; + EODatabaseOperator dbOperator = EODatabaseNothingOperator; + NSDictionary *changedValues = nil; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"dbOpe=%@", dbOpe); + NSAssert(dbOpe, @"No operation"); + + entity = [dbOpe entity]; //OK + dbOperator = [dbOpe databaseOperator]; //OK + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"attributes=%@", attributes); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"dbOperator=%d", + (int)dbOperator); + + switch (dbOperator) + { + case EODatabaseUpdateOperator: + { + changedValues = [dbOpe rowDiffsForAttributes:attributes]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"changedValues %p=%@", + changedValues, changedValues); + + if ([changedValues count] == 0) + isSomethingTodo = NO; + else + { + } + } + break; + + case EODatabaseInsertOperator: + { + changedValues = [dbOpe newRow]; //OK + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"changedValues %p=%@", + changedValues, changedValues); + } + break; + + case EODatabaseDeleteOperator: + { + isSomethingTodo = YES; + } + break; + + case EODatabaseNothingOperator: + { + //Nothing! + } + break; + + default: + { + NSEmitTODO(); + // [self notImplemented:_cmd]; //TODO + } + break; + } + + if (isSomethingTodo) + { + EOAdaptorOperation *adaptorOpe = nil; + NSString *procedureOpeName = nil; + EOAdaptorOperator adaptorOperator = EOAdaptorUndefinedOperator; + EOStoredProcedure *storedProcedure = nil; + + NSDictionary *valuesToWrite = nil; + EOQualifier *lockingQualifier = nil; + + switch (dbOperator) + { + case EODatabaseUpdateOperator: + case EODatabaseDeleteOperator: + { + NSArray *pkAttributes; + NSArray *lockingAttributes; + NSDictionary *dbSnapshot; + + pkAttributes = [self primaryKeyAttributesForAttributes: attributes + entity: entity]; + lockingAttributes = [self lockingAttributesForAttributes: + attributes + entity: entity]; + + dbSnapshot = [dbOpe dbSnapshot]; + lockingQualifier = [self qualifierForLockingAttributes: + lockingAttributes + primaryKeyAttributes: pkAttributes + entity: entity + snapshot: dbSnapshot]; + + NSEmitTODO(); + + //TODO=self lockingNonQualifiableAttributes:##### ret nil + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"lockingQualifier=%@", + lockingQualifier); + + /*MIRKO for UPDATE: + //TODO-NOW + { + if ([self isObjectLockedWithGlobalID:gid] == NO) + { + EOAdaptorOperation *lockOperation; + EOQualifier *qualifier; + EOAttribute *attribute; + NSEnumerator *attrsEnum; + NSArray *attrsUsedForLocking, *primaryKeyAttributes; + NSMutableDictionary *qualifierSnapshot, *lockSnapshot; + NSMutableArray *lockAttributes; + + lockOperation = [EOAdaptorOperation adaptorOperationWithEntity: + entity]; + + attrsUsedForLocking = [entity attributesUsedForLocking]; + primaryKeyAttributes = [entity primaryKeyAttributes]; + + qualifierSnapshot = [NSMutableDictionary + dictionaryWithCapacity:16]; + lockSnapshot = [NSMutableDictionary dictionaryWithCapacity:8]; + lockAttributes = [NSMutableArray arrayWithCapacity:8]; + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"lock start %@", snapshot); + attrsEnum = [primaryKeyAttributes objectEnumerator]; + while ((attribute = [attrsEnum nextObject])) + { + NSString *name = [attribute name]; + EOFLOGObjectLevelArgs(@"EODatabaseContext",@" %@", name); + [lockSnapshot setObject:[snapshot objectForKey:name] + forKey:name]; + } + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"lock stop"); + + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"lock start2"); + attrsEnum = [attrsUsedForLocking objectEnumerator]; + while ((attribute = [attrsEnum nextObject])) + { + NSString *name = [attribute name]; + + if ([primaryKeyAttributes containsObject:attribute] == NO) + { + if ([attribute adaptorValueType] == EOAdaptorBytesType) + { + [lockAttributes addObject:attribute]; + [lockSnapshot setObject:[snapshot + objectForKey:name] + forKey:name]; + } + else + [qualifierSnapshot setObject:[snapshot + objectForKey:name] + forKey:name]; + } + } + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"lock stop2"); + + qualifier = [[[EOAndQualifier alloc] + initWithQualifiers: + [entity qualifierForPrimaryKey: + [entity primaryKeyForGlobalID: + (EOKeyGlobalID *)gid]], + [EOQualifier qualifierToMatchAllValues: + qualifierSnapshot], + nil] + autorelease]; + + if ([lockAttributes count] == 0) + lockAttributes = nil; + if ([lockSnapshot count] == 0) + lockSnapshot = nil; + + [lockOperation setAdaptorOperator:EOAdaptorLockOperator]; + [lockOperation setQualifier:qualifier]; + [lockOperation setAttributes:lockAttributes]; + [lockOperation setChangedValues:lockSnapshot]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"*+ %@", lockSnapshot); + [op addAdaptorOperation:lockOperation]; + } + */ + } + break; + + case EODatabaseInsertOperator: + break; + + case EODatabaseNothingOperator: + break; + } + + adaptorOpe = [EOAdaptorOperation adaptorOperationWithEntity: entity]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"adaptorOpe=%@", + adaptorOpe); + + switch (dbOperator) + { + case EODatabaseInsertOperator: + procedureOpeName = @"EOInsertProcedure"; + adaptorOperator = EOAdaptorInsertOperator; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"changedValues %p=%@", + changedValues, changedValues); + + valuesToWrite = [self valuesToWriteForAttributes: attributes + entity: entity + changedValues: changedValues]; + break; + + case EODatabaseUpdateOperator: + procedureOpeName = @"EOUpdateProcedure"; + adaptorOperator = EOAdaptorUpdateOperator; + valuesToWrite = [self valuesToWriteForAttributes: attributes + entity: entity + changedValues: changedValues]; + break; + + case EODatabaseDeleteOperator: + procedureOpeName = @"EODeleteProcedure"; + adaptorOperator = EOAdaptorDeleteOperator; + /* + MIRKO + NSMutableArray *newKeys = [[[NSMutableArray alloc] + initWithCapacity:count] + autorelease]; + NSMutableArray *newVals = [[[NSMutableArray alloc] + initWithCapacity:count] + autorelease]; + + if ([entity isReadOnly] == YES) + { + [NSException raise:NSInvalidArgumentException format:@"%@ -- %@ 0x%x: cannot delete object for readonly entity %@", NSStringFromSelector(_cmd), NSStringFromClass([self class]), self, [entity name]]; + } + + [aOp setAdaptorOperator:EOAdaptorDeleteOperator]; + + count = [primaryKeys count]; + for (i = 0; i < count; i++) + { + EOAttribute *attribute = [primaryKeys objectAtIndex:i]; + NSString *key = [attribute name]; + id val; + if ([attribute isFlattened] == NO) + { + // Turbocat + //val = [object storedValueForKey:key]; + if (currentSnapshot) { + val = [currentSnapshot objectForKey:key]; + } + + if (!val) { + [NSException raise:NSInvalidArgumentException format:@"%@ -- %@ 0x%x: cannot delete object (snapshot) '%@' for unkown primarykey value '%@'", NSStringFromSelector(_cmd), NSStringFromClass([self class]), self, currentSnapshot, key]; + } + + if (val == nil) + val = null; + + [newKeys addObject:key]; + [newVals addObject:val]; + } + } + + row = [NSDictionary dictionaryWithObjects:newVals + forKeys:newKeys]; + + [aOp setQualifier:[entity qualifierForPrimaryKey:[op newRow]]]; + + ==>NO? in _commitTransaction [self forgetSnapshotForGlobalID:[op globalID]]; + */ + break; + + case EODatabaseNothingOperator: + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"Db Ope %@ for Nothing !!!", dbOpe); + //Nothing? + break; + + default: + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + break; + } + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"adaptorOperator=%d", + adaptorOperator); + + // only for insert ?? + storedProcedure = [entity storedProcedureForOperation: procedureOpeName]; + if (storedProcedure) + { + adaptorOperator = EOAdaptorStoredProcedureOperator; + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + } + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"adaptorOperator=%d", + adaptorOperator); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"adaptorOpe=%@", adaptorOpe); + + if (adaptorOpe) + { + [adaptorOpe setAdaptorOperator: adaptorOperator]; + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"valuesToWrite=%@", + valuesToWrite); + + if (valuesToWrite) + [adaptorOpe setChangedValues: valuesToWrite]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"lockingQualifier=%@", + lockingQualifier); + + if (lockingQualifier) + [adaptorOpe setQualifier: lockingQualifier]; + + [dbOpe addAdaptorOperation: adaptorOpe]; + } + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"adaptorOpe=%@", + adaptorOpe); + } + + EOFLOGObjectFnStop(); +} + +- (void) createAdaptorOperationsForDatabaseOperation: (EODatabaseOperation*)dbOpe +{ + //OK for Update - Test for others + NSArray *attributesToSave = nil; + NSMutableArray *attributes = nil; + int i, count; + EODatabaseOperator dbOperator = EODatabaseNothingOperator; + EOEntity *entity = [dbOpe entity]; //OK + NSDictionary *rowDiffs = nil; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"dbOpe=%@", dbOpe); + + [self processSnapshotForDatabaseOperation: dbOpe]; //OK + dbOperator = [dbOpe databaseOperator]; //OK + + if (dbOperator == EODatabaseUpdateOperator) //OK + { + rowDiffs = [dbOpe rowDiffs]; + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"rowDiffs=%@", rowDiffs); + } + + attributesToSave = [entity _attributesToSave]; //OK for update, OK for insert + attributes = [NSMutableArray array]; + + count = [attributesToSave count]; + for (i = 0; i < count; i++) + { + EOAttribute *attribute = [attributesToSave objectAtIndex: i]; //OK + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"attribute=%@", attribute); + + if (![attribute isFlattened] && ![attribute isDerived]) //VERIFY + { + [attributes addObject: attribute]; + + if ([rowDiffs objectForKey: [attribute name]] + && [attribute isReadOnly]) + { + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO: excption ??? + } + } + } + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"dbOpe=%@", dbOpe); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"attributes=%@", attributes); + + [self createAdaptorOperationsForDatabaseOperation: dbOpe + attributes: attributes]; +} + +- (NSArray*) orderAdaptorOperations +{ + //seems OK + NSMutableArray *orderedAdaptorOpe = (NSMutableArray*)[NSMutableArray array]; + + EOFLOGObjectFnStart(); + + //MIRKO + if (_delegateRespondsTo.willOrderAdaptorOperations == YES) + orderedAdaptorOpe = (NSMutableArray*) + [_delegate databaseContext: self + willOrderAdaptorOperationsFromDatabaseOperations: + NSAllMapTableValues(_dbOperationsByGlobalID)]; + else + { + NSArray *entities = nil; + NSMutableArray *adaptorOperations = [NSMutableArray array]; + NSMapEnumerator dbOpeEnum; + EOGlobalID *gid = nil; + EODatabaseOperation *dbOpe = nil; + NSHashTable *entitiesHashTable = NSCreateHashTable(NSNonOwnedPointerHashCallBacks,32); + + dbOpeEnum = NSEnumerateMapTable(_dbOperationsByGlobalID); + + while (NSNextMapEnumeratorPair(&dbOpeEnum, (void **)&gid, + (void **)&dbOpe)) + { + NSArray *dbOpeAdaptorOperations = [dbOpe adaptorOperations]; + int i, count = [dbOpeAdaptorOperations count]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"dbOpe=%@", dbOpe); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"gid=%@", gid); + + for (i = 0; i < count; i++) + { + EOAdaptorOperation *adaptorOpe = [dbOpeAdaptorOperations + objectAtIndex: i]; + EOEntity *entity = nil; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"adaptorOpe=%@", + adaptorOpe); + + [adaptorOperations addObject: adaptorOpe]; + entity = [adaptorOpe entity]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"entity=%@", + [entity name]); + NSHashInsertIfAbsent(entitiesHashTable, entity); + } + } + + entities = NSAllHashTableObjects(entitiesHashTable); + NSFreeHashTable(entitiesHashTable); + + entitiesHashTable = NULL; + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"entities=%@", entities); + + { + NSArray *entityNameOrderingArray = [self entityNameOrderingArrayForEntities:entities]; + int iAdaptoOpe = 0; + int adaptorOpeCount = [adaptorOperations count]; + int entitiesCount = [entityNameOrderingArray count]; + int iEntity; + + for (iEntity = 0; iEntity < entitiesCount; iEntity++) + { + EOEntity *entity = [entityNameOrderingArray + objectAtIndex: iEntity]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"entity=%@", + [entity name]); + + for (iAdaptoOpe = 0; iAdaptoOpe < adaptorOpeCount; iAdaptoOpe++) + { + EOAdaptorOperation *adaptorOpe = [adaptorOperations + objectAtIndex: iAdaptoOpe]; + EOEntity *opeEntity = [adaptorOpe entity]; + + if (opeEntity == entity) + [orderedAdaptorOpe addObject: adaptorOpe]; + } + } + + NSAssert2([orderedAdaptorOpe count] == adaptorOpeCount, + @"Different ordered (%d) an unordered adaptor operations count (%d)", + [orderedAdaptorOpe count], + adaptorOpeCount); + } + } + + EOFLOGObjectFnStop(); + + return orderedAdaptorOpe; +} + +- (id) entitiesOnWhichThisEntityDepends: (EOEntity*)entity +{ + NSMutableArray *entities = nil; + NSArray *relationships = nil; + int i, count; + + EOFLOGObjectFnStart(); + + relationships = [entity relationships]; + count = [relationships count]; + + for (i = 0; i < count; i++) + { + EORelationship *relationship = [relationships objectAtIndex: i]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"relationship=%@", + relationship); + + if (![relationship isToMany]) //If to many: do nothing + { + if ([relationship isFlattened]) + { + NSEmitTODO(); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"relationship=%@", relationship); + [self notImplemented: _cmd]; //TODO-NOW + } + else + { + //Here ?? + EOEntity *destinationEntity = [relationship destinationEntity]; + EORelationship *inverseRelationship = [relationship + anyInverseRelationship]; + + if ([inverseRelationship isToMany]) + { + //Do nothing ? + } + else + { + if ([inverseRelationship propagatesPrimaryKey]) + { + //OK + if (!entities) + entities = [NSMutableArray array]; + + [entities addObject: destinationEntity]; + } + else + { + if ([inverseRelationship ownsDestination]) + { + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + } + } + } + } + } + } + + EOFLOGObjectFnStop(); + + return entities; +} + +- (NSArray*)entityNameOrderingArrayForEntities: (NSArray*)entities +{ + //TODO + NSMutableArray *ordering = [NSMutableArray array]; + NSMutableSet *orderedEntities = [NSMutableSet set]; + /*EODatabase *database = [self database]; + NSArray *models = [database models];*/ + NSMutableDictionary *dependsDict = [NSMutableDictionary dictionary]; + int i, count = [entities count]; + + //TODO NSArray* originalOrdering=... + /*TODO for each mdoel: + userInfo (ret nil) + */ + + for (i = 0; i < count; i++) + { + //OK + EOEntity *entity=[entities objectAtIndex: i]; + NSArray *dependsEntities = [self + entitiesOnWhichThisEntityDepends: entity]; + + if ([dependsEntities count]) + [dependsDict setObject: dependsEntities + forKey: [entity name]]; + } + + ordering = [NSMutableArray array]; + for (i = 0; i < count; i++) + { + EOEntity *entity = [entities objectAtIndex: i]; + [self insertEntity: entity + intoOrderingArray: ordering + withDependencies: dependsDict + processingSet: orderedEntities]; + } + //TODO + /* + model userInfo //ret nil + setUserInfo: {EOEntityOrdering = ordering; } + */ + + return ordering; +} + +- (BOOL) isValidQualifierTypeForAttribute: (EOAttribute*)attribute +{ + //OK + BOOL isValid = NO; + EOEntity *entity = nil; + EOModel *model = nil; + EODatabase *database = nil; + EOAdaptor *adaptor = nil; + NSString *externalType = nil; + + EOFLOGObjectFnStart(); + + entity = [attribute entity]; + + NSAssert1(entity, @"No entity for attribute %@", attribute); + + model = [entity model]; + database = [self database]; + adaptor = [database adaptor]; + externalType = [attribute externalType]; + isValid = [adaptor isValidQualifierType: externalType + model: model]; + + //TODO REMOVE + if (!isValid) + { + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"attribute=%@", + attribute); + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"externalType=%@", + externalType); + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"entity name=%@", + entity); + } + + EOFLOGObjectFnStop(); + + return isValid; +} + +- (id) lockingNonQualifiableAttributes: (NSArray*)attributes +{ + //TODO finish + EOEntity *entity = nil; + NSArray *attributesUsedForLocking = nil; + int i, count = 0; + + count = [attributes count]; + + for (i = 0; i < count; i++) + { + id attribute = [attributes objectAtIndex: i]; + + if (!entity) + { + entity = [attribute entity]; + attributesUsedForLocking = [entity attributesUsedForLocking]; + } + + if (![self isValidQualifierTypeForAttribute: attribute]) + { + NSEmitTODO(); + // [self notImplemented:_cmd]; //TODO + } + else + { + NSEmitTODO(); + //Nothing ?? + // [self notImplemented:_cmd]; //TODO ?? + } + } + + return nil;//?? +} + +- (NSArray*) lockingAttributesForAttributes: (NSArray*)attributes + entity: (EOEntity*)entity +{ + //TODO + NSArray *retAttributes = nil; + int i, count = 0; + NSArray *attributesUsedForLocking = nil; + + EOFLOGObjectFnStart(); + + attributesUsedForLocking = [entity attributesUsedForLocking]; + count = [attributes count]; + + for (i = 0; i < count; i++) + { + id attribute = [attributes objectAtIndex: i]; + //do this on 1st only + BOOL isFlattened = [attribute isFlattened]; + + if (isFlattened) + { + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + } + else + { + NSArray *rootAttributesUsedForLocking = [entity rootAttributesUsedForLocking]; + + retAttributes = rootAttributesUsedForLocking; + } + } + + EOFLOGObjectFnStop(); + + return retAttributes; //TODO +} + +- (NSArray*) primaryKeyAttributesForAttributes: (NSArray*)attributes + entity: (EOEntity*)entity +{ + //TODO + NSArray *retAttributes = nil; + int i, count = 0; + + EOFLOGObjectFnStart(); +//TODO + + count = [attributes count]; + + for (i = 0; i < count; i++) + { + id attribute = [attributes objectAtIndex: i]; + BOOL isFlattened = [attribute isFlattened]; + + //call isFlattened on 1st only + if (isFlattened) + { + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + } + else + { + NSArray *primaryKeyAttributes = [entity primaryKeyAttributes]; + + retAttributes = primaryKeyAttributes; + } + } + + EOFLOGObjectFnStop(); + + return retAttributes; +} + +- (EOQualifier*) qualifierForLockingAttributes: (NSArray*)attributes + primaryKeyAttributes: (NSArray*)primaryKeyAttributes + entity: (EOEntity*)entity + snapshot: (NSDictionary*)snapshot +{ + //OK + EOQualifier *qualifier = nil; + NSMutableArray *qualifiers = nil; + int which; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"attributes=%@", attributes); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"primaryKeyAttributes=%@", + primaryKeyAttributes); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"snapshot=%@", snapshot); + + //First use primaryKeyAttributes, next use attributes + for (which = 0; which < 2; which++) + { + NSArray *array = (which == 0 ? primaryKeyAttributes : attributes); + int i, count = [array count]; + + for (i = 0; i < count; i++) + { + EOAttribute *attribute = [array objectAtIndex: i]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"attribute=%@", + attribute); + + if (which == 0 || ![primaryKeyAttributes containsObject: attribute])// Test if we haven't already processed it + { + if (![self isValidQualifierTypeForAttribute: attribute]) + { + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + } + else + { + NSString *attributeName = nil; + NSString *snapName = nil; + id value = nil; + EOQualifier *aQualifier = nil; + + attributeName = [attribute name]; + NSAssert1(attributeName, @"no attribute name for attribute %@", attribute); + + snapName = [entity snapshotKeyForAttributeName: attributeName]; + NSAssert2(snapName, @"no snapName for attribute %@ in entity %@", attributeName, [entity name]); + + value = [snapshot objectForKey:snapName]; + + if (!value) + { + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"NO VALUE"); + } + + NSAssert3(value, @"no value for %@ in %p %@", snapName, + snapshot, snapshot); + + aQualifier = [EOKeyValueQualifier + qualifierWithKey: attributeName + operatorSelector: @selector(isEqualTo:) + value: value]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"aQualifier=%@", + aQualifier); + + if (!qualifiers) + qualifiers = [NSMutableArray array]; + + [qualifiers addObject: aQualifier]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"qualifiers=%@", + qualifiers); + } + } + } + } + + if ([qualifiers count] == 1) + qualifier = [qualifiers objectAtIndex: 0]; + else + qualifier = [EOAndQualifier qualifierWithQualifierArray: qualifiers]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"qualifier=%@", qualifier); + + EOFLOGObjectFnStop(); + + return qualifier; +} + +- (void) insertEntity: (EOEntity*)entity + intoOrderingArray: (NSMutableArray*)orderingArray + withDependencies: (NSDictionary*)dependencies + processingSet: (NSMutableSet*)processingSet +{ + //TODO: manage dependencies {CustomerCredit = (); } + // and processingSet + [orderingArray addObject: entity]; + [processingSet addObject: [entity name]]; +} + + +- (void) processSnapshotForDatabaseOperation: (EODatabaseOperation*)dbOpe +{ + //Near OK + EOAdaptor *adaptor = [_database adaptor];//OK + EOEntity *entity = [dbOpe entity];//OK + NSDictionary *newRow = nil; + NSDictionary *dbSnapshot = nil; + NSEnumerator *attrNameEnum = nil; + id attrName = nil; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"dbOpe=%@", dbOpe); + + newRow = [dbOpe newRow]; //OK{a3code = Q77; code = Q7; numcode = 007; } //ALLOK + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"newRow %p=%@", newRow, newRow); + + dbSnapshot = [dbOpe dbSnapshot]; + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"dbSnapshot %p=%@", + dbSnapshot, dbSnapshot); + + attrNameEnum = [newRow keyEnumerator]; + + while ((attrName = [attrNameEnum nextObject])) + { + EOAttribute *attribute = [entity attributeNamed: attrName]; + id newRowValue = nil; + id dbSnapshotValue = nil; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"attribute=%@", attribute); + + newRowValue = [newRow objectForKey:attrName]; + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"newRowValue=%@", + newRowValue); + + dbSnapshotValue = [dbSnapshot objectForKey: attrName]; + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"dbSnapshotValue=%@", + dbSnapshotValue); + + if (dbSnapshotValue && ![newRowValue isEqual: dbSnapshotValue]) + { + id adaptorValue = [adaptor fetchedValueForValue: newRowValue + attribute: attribute]; //this call is OK + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"adaptorValue=%@", + adaptorValue); + //TODO-NOW SO WHAT ?? may be replacing newRow diff values by adaptorValue if different ???? + } + } + + EOFLOGObjectFnStop(); +} + + +- (NSDictionary*) valuesToWriteForAttributes: (NSArray*)attributes + entity: (EOEntity*)entity + changedValues: (NSDictionary*)changedValues +{ + //NEAR OK + NSMutableDictionary *valuesToWrite = [NSMutableDictionary dictionary]; + BOOL isReadOnlyEntity = NO; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"attributes=%@", attributes); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"entity=%@", [entity name]); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"changedValues=%@", + changedValues); + + isReadOnlyEntity = [entity isReadOnly]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"isReadOnlyEntity=%s", + (isReadOnlyEntity ? "YES" : "NO")); + + if (isReadOnlyEntity) + { + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + } + else + { + int i, count = [attributes count]; + + for (i = 0; i < count; i++) + { + EOAttribute *attribute = [attributes objectAtIndex: i]; + BOOL isReadOnly = [attribute isReadOnly]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"attribute=%@", + attribute); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"isReadOnly=%s", + (isReadOnly ? "YES" : "NO")); + + if (isReadOnly) + { + NSEmitTODO(); + NSDebugMLog(@"attribute=%@",attribute); + [self notImplemented: _cmd]; //TODO + } + else + { + NSString *attrName = [attribute name]; + NSString *snapName = nil; + id value = nil; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"attrName=%@", + attrName); + + snapName = [entity snapshotKeyForAttributeName: attrName]; + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"snapName=%@", + snapName); + + value = [changedValues objectForKey: snapName]; + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"value=%@", value); + + if (value) + [valuesToWrite setObject: value + forKey: attrName]; + } + } + } + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"valuesToWrite=%@", + valuesToWrite); + + EOFLOGObjectFnStop(); + + return valuesToWrite; +} + +@end + + +@implementation EODatabaseContext(EOBatchFaulting) + +- (void)batchFetchRelationship: (EORelationship *)relationship + forSourceObjects: (NSArray *)objects + editingContext: (EOEditingContext *)editingContext +{ // TODO + NSMutableArray *qualifierArray, *valuesArray, *toManySnapshotArray; + NSMutableDictionary *values; + NSArray *array; + NSEnumerator *objsEnum, *joinsEnum, *keyEnum; + NSString *key; + EOFetchSpecification *fetch; + EOQualifier *qualifier; + EOFault *fault; + EOJoin *join; + BOOL equal; + int i, count; + id object; + + qualifierArray = [NSMutableArray array]; + valuesArray = [NSMutableArray array]; + toManySnapshotArray = [NSMutableArray array]; + + objsEnum = [objects objectEnumerator]; + while ((object = [objsEnum nextObject])) + { + values = [NSMutableDictionary dictionaryWithCapacity: 4]; + + fault = [object valueForKey: [relationship name]]; + [EOFault clearFault: fault]; + + joinsEnum = [[relationship joins] objectEnumerator]; + while ((join = [joinsEnum nextObject])) + { + [values setObject: [object valueForKey: [[join sourceAttribute] name]] + forKey: [[join destinationAttribute] name]]; + } + + [valuesArray addObject: values]; + [toManySnapshotArray addObject: [NSMutableArray array]]; + + [qualifierArray addObject: [EOQualifier qualifierToMatchAllValues: + values]]; + } + + if ([qualifierArray count] == 1) + qualifier = [qualifierArray objectAtIndex: 0]; + else + qualifier = [EOOrQualifier qualifierWithQualifierArray: qualifierArray]; + + fetch = [EOFetchSpecification fetchSpecificationWithEntityName: + [[relationship destinationEntity] name] + qualifier: qualifier + sortOrderings: nil]; + + array = [self objectsWithFetchSpecification: fetch + editingContext: editingContext]; + + count = [valuesArray count]; + + objsEnum = [array objectEnumerator]; + while ((object = [objsEnum nextObject])) + { + for (i = 0; i < count; i++) + { + equal = YES; + + values = [valuesArray objectAtIndex: i]; + keyEnum = [values keyEnumerator]; + while ((key = [keyEnum nextObject])) + { + if ([[object valueForKey: key] + isEqual: [values objectForKey:key]] == NO) + { + equal = NO; + break; + } + } + + if (equal == YES) + { + [[[objects objectAtIndex: i] valueForKey: [relationship name]] + addObject: object]; + [[toManySnapshotArray objectAtIndex: i] + addObject: [editingContext globalIDForObject: object]]; + + break; + } + } + } + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"** 3"); +//==> see _registerSnapshot:forSourceGlobalID:relationshipName:editingContext: + + for (i = 0; i < count; i++) + [_database recordSnapshot: [toManySnapshotArray objectAtIndex: i] + forSourceGlobalID: + [editingContext globalIDForObject: [objects objectAtIndex: i]] + relationshipName: [relationship name]]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"** 4"); +} + + +@implementation EODatabaseContext (EODatabaseContextPrivate) + +- (void) _fireArrayFault: (id)object +{ + //OK ?? + BOOL fetchIt = YES; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"object=%p", object); + + if (_delegateRespondsTo.shouldFetchObjectFault == YES) + fetchIt = [_delegate databaseContext: self + shouldFetchObjectFault: object]; + + if (fetchIt) + { + /*Class targetClass = Nil; + void *extraData = NULL;*/ + EOAccessArrayFaultHandler *handler = [EOFault handlerForFault:object]; + EOEditingContext *context = [handler editingContext]; + NSString *relationshipName= [handler relationshipName]; + EOKeyGlobalID *gid = [handler sourceGlobalID]; + NSArray *objects = nil; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"relationshipName=%@", + relationshipName); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"gid=%@", gid); + + objects = [context objectsForSourceGlobalID: gid + relationshipName: relationshipName + editingContext: context]; + + [EOFault clearFault: object]; //?? + /* in clearFault + [handler faultWillFire:object]; + targetClass=[handler targetClass]; + extraData=[handler extraData]; + [handler release]; + */ + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"NEAR FINISHED 1 object count=%d %p %@", + [object count], + object, + object); + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"NEAR FINISHED 1 objects count=%d %p %@", + [objects count], + objects, + objects); + + if (objects != object) + { + //No, not needed [object removeObjectsInArray:objects];//Because some objects may be here. We don't want duplicate. It's a hack because I don't see why there's objects in object ! + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"NEAR FINISHED 1 object count=%d %p %@", + [object count], + object, + object); + + [object addObjectsFromArray: objects]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"NEAR FINISHED 2 object count=%d %@", + [object count], + object); + } + } + //END! +/* +} + +- (void)_batchToMany:(id)fault + withHandler:(EOAccessArrayFaultHandler *)handler +{ +*/ + +/* + EOAccessArrayFaultHandler *usedHandler, *firstHandler, *lastHandler; + EOAccessArrayFaultHandler *bufHandler; + NSMutableDictionary *batchBuffer; + EOEditingContext *context; + NSMutableArray *objects; + EOKeyGlobalID *gid; + EOEntity *entity; + EORelationship *relationship; + unsigned int maxBatch; + BOOL batch = YES, changeBatch = NO; + + + gid = [handler sourceGlobalID];//OK + context = [handler editingContext];//OK + + entity = [_database entityNamed:[gid entityName]];//-done + relationship = [entity relationshipNamed:[handler relationshipName]];//-done + maxBatch = [relationship numberOfToManyFaultsToBatchFetch];//-done + + batchBuffer = [_batchToManyFaultBuffer objectForKey:[entity name]]; + bufHandler = [batchBuffer objectForKey:[relationship name]]; + + objects = [NSMutableArray array]; + + [objects addObject:[context objectForGlobalID:gid]];//-done + + firstHandler = lastHandler = nil; + usedHandler = handler; + + if (bufHandler && [bufHandler isEqual:usedHandler] == YES) + changeBatch = YES; + + if (maxBatch > 1) + { + maxBatch--; + + while (maxBatch--) + { + if (lastHandler == nil) + { + usedHandler = (EOAccessArrayFaultHandler *)[usedHandler + previous]; + + if (usedHandler) + firstHandler = usedHandler; + else + lastHandler = usedHandler = (EOAccessArrayFaultHandler *) + [handler next]; + } + else + { + usedHandler = (EOAccessArrayFaultHandler *)[lastHandler next]; + + if (usedHandler) + lastHandler = usedHandler; + } + + if (usedHandler == nil) + break; + + if (bufHandler && [bufHandler isEqual:usedHandler] == YES) + changeBatch = YES; + + [objects addObject:[context objectForGlobalID:[usedHandler + sourceGlobalID]]]; + } + } + + if (firstHandler == nil) + firstHandler = handler; + if (lastHandler == nil) + lastHandler = handler; + + usedHandler = (id)[firstHandler previous]; + bufHandler = (id)[lastHandler next]; + if (usedHandler) + [usedHandler _linkNext:bufHandler]; + + usedHandler = bufHandler; + if (usedHandler) + { + [usedHandler _linkPrev:[firstHandler previous]]; + if (bufHandler == nil) + bufHandler = usedHandler; + } + + if (changeBatch == YES) + { + if (bufHandler) + [batchBuffer setObject:bufHandler + forKey:[relationship name]]; + else + [batchBuffer removeObjectForKey:[relationship name]]; + } + + [self batchFetchRelationship:relationship + forSourceObjects:objects + editingContext:context]; +*/ + + EOFLOGObjectFnStop(); +} + +- (void) _fireFault: (id)object +{ + //TODO + BOOL fetchIt = YES;//MIRKO + + EOFLOGObjectFnStart(); + + //MIRKO + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"Fire Fault: object %p of class %@", + object,[object class]); + + if (_delegateRespondsTo.shouldFetchObjectFault == YES) + fetchIt = [_delegate databaseContext: self + shouldFetchObjectFault: object]; + + if (fetchIt) + { + EOAccessFaultHandler *handler; + EOEditingContext *context; + EOGlobalID *gid; + NSDictionary *snapshot; + EOEntity *entity = nil; + NSString *entityName = nil; + + handler = (EOAccessFaultHandler *)[EOFault handlerForFault: object]; + context = [handler editingContext]; + gid = [handler globalID]; + snapshot = [self snapshotForGlobalID: gid]; //nil + + if (snapshot) + { + //TODO _fireFault snapshot + NSEmitTODO(); +// [self notImplemented: _cmd]; //TODO + } + + entity = [self entityForGlobalID: gid]; + entityName = [entity name]; + + if ([entity cachesObjects]) + { + //TODO _fireFault [entity cachesObjects] + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + } + + //??? generation # EOAccessGenericFaultHandler//ret 2 + { + EOAccessFaultHandler *previousHandler; + EOAccessFaultHandler *nextHandler; + EOFetchSpecification *fetchSpecif; + NSArray *objects; + EOQualifier *qualifier; + /*int maxNumberOfInstancesToBatchFetch = + [entity maxNumberOfInstancesToBatchFetch]; + NSDictionary *snapshot = [self snapshotForGlobalID: gid];*///nil //TODO use it ! + NSDictionary *pk = [entity primaryKeyForGlobalID: gid]; + EOQualifier *pkQualifier = [entity qualifierForPrimaryKey: pk]; + NSMutableArray *qualifiers = [NSMutableArray array]; + + [qualifiers addObject: pkQualifier]; + + previousHandler = (EOAccessFaultHandler *)[handler previous]; + nextHandler = (EOAccessFaultHandler *)[handler next]; //nil + + fetchSpecif = [[EOFetchSpecification new] autorelease]; + [fetchSpecif setEntityName: entityName]; + + qualifier = [EOOrQualifier qualifierWithQualifierArray: qualifiers]; + + [fetchSpecif setQualifier: qualifier]; + + objects = [self objectsWithFetchSpecification: fetchSpecif + editingContext: context]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"objects %p=%@ class=%@", + objects, objects, [objects class]); + } + } + + EOFLOGObjectFnStop(); +} + +/* +- (void)_batchToOne:(id)fault + withHandler:(EOAccessFaultHandler *)handler +{ + EOAccessFaultHandler *usedHandler, *firstHandler, *lastHandler; + EOAccessFaultHandler *bufHandler; + EOFetchSpecification *fetch; + EOEditingContext *context; + EOKeyGlobalID *gid; + EOQualifier *qualifier; + EOEntity *entity; + NSMutableArray *qualifierArray; + BOOL batch = YES, changeBatch = NO; + unsigned int maxBatch; + + if (_delegateRespondsTo.shouldFetchObjectFault == YES)//-done + batch = [_delegate databaseContext:self + shouldFetchObjectFault:fault];//-done + + if (batch == NO)//-done + return;//-done + + gid = [handler globalID];//-done + context = [handler editingContext];//-done + + entity = [_database entityNamed:[gid entityName]];//-done + maxBatch = [entity maxNumberOfInstancesToBatchFetch];//-done + + bufHandler = [_batchFaultBuffer objectForKey:[entity name]]; + + firstHandler = lastHandler = nil; + usedHandler = handler; + + if (bufHandler && [bufHandler isEqual:usedHandler] == YES) + changeBatch = YES; + + if (maxBatch <= 1) + { + qualifier = [entity qualifierForPrimaryKey: + [entity primaryKeyForGlobalID:gid]]; + } + else + { + qualifierArray = [NSMutableArray array]; + + [qualifierArray addObject: + [entity qualifierForPrimaryKey: + [entity primaryKeyForGlobalID:gid]]]; + + maxBatch--; + + while (maxBatch--) + { + if (lastHandler == nil) + { + usedHandler = (EOAccessFaultHandler *)[usedHandler previous]; + + if (usedHandler) + firstHandler = usedHandler; + else + lastHandler = usedHandler = (EOAccessFaultHandler *)[handler + next]; + } + else + { + usedHandler = (EOAccessFaultHandler *)[lastHandler next]; + + if (usedHandler) + lastHandler = usedHandler; + } + + if (usedHandler == nil) + break; + + if (changeBatch == NO && + bufHandler && [bufHandler isEqual:usedHandler] == YES) + changeBatch = YES; + + [qualifierArray addObject: + [entity qualifierForPrimaryKey: + [entity primaryKeyForGlobalID: + [usedHandler globalID]]]]; + } + + qualifier = [[[EOOrQualifier alloc] + initWithQualifierArray:qualifierArray] autorelease]; + } + + if (firstHandler == nil) + firstHandler = handler; + if (lastHandler == nil) + lastHandler = handler; + + usedHandler = (id)[firstHandler previous]; + bufHandler = (id)[lastHandler next]; + if (usedHandler) + [usedHandler _linkNext:bufHandler]; + + usedHandler = bufHandler; + if (usedHandler) + { + [usedHandler _linkPrev:[firstHandler previous]]; + if (bufHandler == nil) + bufHandler = usedHandler; + } + + if (changeBatch == YES) + { + if (bufHandler) + [_batchFaultBuffer setObject:bufHandler + forKey:[entity name]]; + else + [_batchFaultBuffer removeObjectForKey:[entity name]]; + } + + fetch = [EOFetchSpecification fetchSpecificationWithEntityName:[entity name] + qualifier:qualifier + sortOrderings:nil];//-done + + [context objectsWithFetchSpecification:fetch];//-done +}*/ + + +// Clear all the faults for the relationship pointed by the source objects and +// make sure to perform only a single, efficient, fetch (two fetches if the +// relationship is many to many). + +- (void)_addBatchForGlobalID: (EOKeyGlobalID *)globalID + fault: (EOFault *)fault +{ + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"globalID=%@", globalID); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"fault=%@", fault); + + if (fault) + { + EOAccessGenericFaultHandler *handler = nil; + NSString *entityName = [globalID entityName]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"entityName=%@", + entityName); + + handler = [_batchFaultBuffer objectForKey: entityName]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"handler=%@", handler); + + if (handler) + { + [(EOAccessGenericFaultHandler *) + [EOFault handlerForFault: fault] + linkAfter: handler + usingGeneration: [handler generation]]; + } + else + { + handler = (EOAccessGenericFaultHandler *)[EOFault handlerForFault: + fault]; + + NSAssert1(handler, @"No handler for fault:%@", fault); + + [_batchFaultBuffer setObject: handler + forKey: entityName]; + } + } + + EOFLOGObjectFnStop(); +} + +- (void)_removeBatchForGlobalID: (EOKeyGlobalID *)globalID + fault: (EOFault *)fault +{ + EOAccessGenericFaultHandler *handler, *prevHandler, *nextHandler; + NSString *entityName = [globalID entityName]; + + handler = (EOAccessGenericFaultHandler *)[EOFault handlerForFault: fault]; + + prevHandler = [handler previous]; + nextHandler = [handler next]; + + if (prevHandler) + [prevHandler _linkNext: nextHandler]; + if (nextHandler) + [nextHandler _linkPrev: prevHandler]; + + if ([_batchFaultBuffer objectForKey: entityName] == handler) + { + if (prevHandler) + [_batchFaultBuffer setObject: prevHandler + forKey: entityName]; + else if (nextHandler) + [_batchFaultBuffer setObject: nextHandler + forKey: entityName]; + else + [_batchFaultBuffer removeObjectForKey: entityName]; + } +} + +- (void)_addToManyBatchForSourceGlobalID: (EOKeyGlobalID *)globalID + relationshipName: (NSString *)relationshipName + fault: (EOFault *)fault +{ + if (fault) + { + NSMutableDictionary *buf; + EOAccessGenericFaultHandler *handler; + NSString *entityName = [globalID entityName]; + + buf = [_batchToManyFaultBuffer objectForKey: entityName]; + + if (buf == nil) + { + buf = [NSMutableDictionary dictionaryWithCapacity: 8]; + [_batchToManyFaultBuffer setObject: buf + forKey: entityName]; + } + + handler = [buf objectForKey: relationshipName]; + + if (handler) + { + [(EOAccessGenericFaultHandler *) + [EOFault handlerForFault: fault] + linkAfter: handler + usingGeneration: [handler generation]]; + } + else + [buf setObject: [EOFault handlerForFault: fault] + forKey: relationshipName]; + } +} + +@end + + +@implementation EODatabaseContext (EODatabaseSnapshotting) + +- (void)recordSnapshot: (NSDictionary *)snapshot + forGlobalID: (EOGlobalID *)gid +{ + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"self=%p database=%p", + self, _database); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"self=%p _uniqueStack %p=%@", + self, _uniqueStack, _uniqueStack); + + if ([_uniqueStack count] > 0) + { + NSMutableDictionary *snapshots = [_uniqueStack lastObject]; + + [snapshots setObject: snapshot + forKey: gid]; + } + else + { + NSEmitTODO(); + NSWarnLog(@"_uniqueStack is empty. May be there's no runing transaction !"); + + [self notImplemented: _cmd]; //TODO + } + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"self=%p _uniqueStack %p=%@", + self, _uniqueStack, _uniqueStack); + + EOFLOGObjectFnStop(); +} + +- (NSDictionary *)snapshotForGlobalID: (EOGlobalID *)gid + after: (NSTimeInterval)ti +{ + [self notImplemented: _cmd]; + return nil; +} + +- (NSDictionary *)snapshotForGlobalID: (EOGlobalID *)gid +{ + //OK + NSDictionary *snapshot = nil; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"self=%p database=%p", + self, _database); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"gid %p=%@", gid, gid); + + snapshot = [self localSnapshotForGlobalID: gid]; + + if (!snapshot) + { + NSAssert(_database, @"No database"); + snapshot = [_database snapshotForGlobalID: gid]; + } + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"snapshot for gid %@: %p %@", + gid, snapshot, snapshot); + + EOFLOGObjectFnStop(); + + return snapshot; +} + +- (void)recordSnapshot: (NSArray *)gids + forSourceGlobalID: (EOGlobalID *)gid + relationshipName: (NSString *)name +{ + EOFLOGObjectFnStart(); + + NSEmitTODO(); + + [self notImplemented: _cmd]; //TODO +/* + NSMutableDictionary *toMany = [_toManySnapshots objectForKey:gid]; + + if (toMany == nil) + { + toMany = [NSMutableDictionary dictionaryWithCapacity:16]; + [_toManySnapshots setObject:toMany + forKey:gid]; + } + + [toMany setObject:gids + forKey:name]; +*/ + + EOFLOGObjectFnStop(); +} + +- (NSArray *)snapshotForSourceGlobalID: (EOGlobalID *)gid + relationshipName: (NSString *)name +{ + NSArray *snapshot = nil; + + EOFLOGObjectFnStart(); + NSEmitTODO(); + + [self notImplemented: _cmd]; //TODO +/* + + snapshot = [[_toManySnapshots objectForKey:gid] objectForKey:name]; + if (!snapshot) + snapshot=[_database snapshotForSourceGlobalID:gid + relationshipName:name]; +*/ + + EOFLOGObjectFnStop(); + + return snapshot; +} + +- (NSDictionary *)localSnapshotForGlobalID: (EOGlobalID *)gid +{ + //OK + NSDictionary *snapshot = nil; + int i, snapshotsDictCount = 0; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"self=%p database=%p", + self, _database); + + snapshotsDictCount = [_uniqueStack count]; + + for (i = 0; !snapshot && i < snapshotsDictCount; i++) + { + NSDictionary *snapshots = [_uniqueStack objectAtIndex: i]; + snapshot = [snapshots objectForKey: gid]; + } + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"snapshot for gid %@: %p %@", + gid, snapshot, snapshot); + + EOFLOGObjectFnStop(); + + return snapshot; +} + +- (NSArray *)localSnapshotForSourceGlobalID: (EOGlobalID *)gid + relationshipName: (NSString *)name +{ + NSArray *snapshot = nil; + + //TODO + EOFLOGObjectFnStart(); + NSEmitTODO(); + + [self notImplemented: _cmd]; //TODO +/* + return [[_toManySnapshots objectForKey:gid] objectForKey:name]; +*/ + + EOFLOGObjectFnStop(); + + return snapshot; +} + +- (void)forgetSnapshotForGlobalID: (EOGlobalID *)gid +{ + //TODO-VERIFY deleteStack + EOFLOGObjectFnStart(); + + if ([_uniqueStack count] > 0) + { + NSMutableDictionary *snapshots = [_uniqueStack lastObject]; + + //call _deleteStack lastObject + [snapshots removeObjectForKey: gid]; + snapshots = [_uniqueArrayStack lastObject]; + [snapshots removeObjectForKey: gid]; + } + + EOFLOGObjectFnStop(); +} + +- (void)forgetSnapshotsForGlobalIDs: (NSArray *)gids +{ + //TODO + NSEmitTODO(); + + [self notImplemented: _cmd]; //TODO +/* + int i, count; + + count = [gids count]; + + for (i=0; i 0) + { + NSMutableDictionary *toManySnapshots = [_uniqueArrayStack lastObject]; + NSArray *keys = [snapshots allKeys]; + int i, count = [keys count]; + + for (i = 0; i < count; i++) + { + id key = [keys objectAtIndex: i]; + NSDictionary *snapshotsDict = [snapshots objectForKey: key]; + NSMutableDictionary *currentSnapshotsDict = + [toManySnapshots objectForKey: key]; + + if (!currentSnapshotsDict) + { + currentSnapshotsDict = (NSMutableDictionary *)[NSMutableDictionary + dictionary]; + [toManySnapshots setObject: currentSnapshotsDict + forKey: key]; + } + + [currentSnapshotsDict addEntriesFromDictionary: snapshotsDict]; + } + } + + EOFLOGObjectFnStop(); +} + +- (void)registerLockedObjectWithGlobalID: (EOGlobalID *)globalID +{ + EOFLOGObjectFnStart(); + + if (_numLocked && (_numLocked+1) % _LOCK_BUFFER == 0) + _lockedObjects = NSZoneRealloc(NULL, _lockedObjects, + (_numLocked+_LOCK_BUFFER)*sizeof(id)); + + _lockedObjects[_numLocked++] = globalID; + + EOFLOGObjectFnStop(); +} + +- (BOOL)isObjectLockedWithGlobalID: (EOGlobalID *)globalID +{ + int i; + + EOFLOGObjectFnStart(); + + for (i = 0; i < _numLocked; i++) + if ([_lockedObjects[i] isEqual: globalID]) + return YES; + + EOFLOGObjectFnStop(); + + return NO; +} + +- (void)initializeObject: (id)object + row: (NSDictionary*)row + entity: (EOEntity*)entity + editingContext: (EOEditingContext*)context +{ + //really near ok + NSArray *relationships = nil; + NSArray *classPropertyAttributeNames = nil; + int i, count = 0; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"object=%d", object); + + classPropertyAttributeNames = [entity classPropertyAttributeNames]; + count = [classPropertyAttributeNames count]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"count=%d", count); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"row=%@", row); + + for (i = 0; i < count; i++) + { + id key = [classPropertyAttributeNames objectAtIndex: i]; + id value = nil; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"key=%@", key); + value = [row objectForKey: key]; + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"value=%@", value); + + [object takeStoredValue: value + forKey: key]; + } + + relationships = [entity _relationshipsToFaultForRow: row]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"relationships=%@", + relationships); + + count = [relationships count]; + + for (i = 0; i < count; i++) + { + id relObject = nil; + EORelationship *relationship = [relationships objectAtIndex: i]; + NSString *relName = [relationship name]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"relationship=%@", + relationship); + + if ([relationship isToMany]) + { + EOGlobalID *gid = [entity globalIDForRow: row]; + + relObject = [self arrayFaultWithSourceGlobalID: gid + relationshipName: [relationship name] + editingContext: context]; + } + else + { + EOMutableKnownKeyDictionary *foreignKeyForSourceRow = + [relationship _foreignKeyForSourceRow: row];//{code = 1; } + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"foreignKeyForSourceRow:%@\n=%@", + foreignKeyForSourceRow, row); + + if (![foreignKeyForSourceRow + containsObjectsNotIdenticalTo: [EONull null]]) + { + NSEmitTODO();//TODO: what to do if rel is mandatory ? + relObject = nil; + } + else + { + EOEntity *destinationEntity = [relationship destinationEntity]; + EOGlobalID *relRowGid = [destinationEntity + globalIDForRow: foreignKeyForSourceRow]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"relRowGid=%@", + relRowGid); + + if ([(EOKeyGlobalID*)relRowGid areKeysAllNulls]) + NSWarnLog(@"All key of relRowGid %p (%@) are nulls", + relRowGid, + relRowGid); + + relObject = [context faultForGlobalID: relRowGid + editingContext: context]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"relObject=%p (%@)", + relObject, [relObject class]); +//end +/* + NSArray *joins = [(EORelationship *)prop joins]; + EOJoin *join; + NSMutableDictionary *row; + EOGlobalID *faultGID; + int h, count; + id value, realValue = nil; + + row = [NSMutableDictionary dictionaryWithCapacity:4]; + + count = [joins count]; + for (h=0; h 0) + { + NSMutableDictionary *snapshotsDict = [[[_uniqueStack lastObject] + retain] autorelease]; + NSMutableDictionary *toManySnapshotsDict = [[[_uniqueArrayStack + lastObject] retain] + autorelease]; + /*NSMutableDictionary *deleteSnapshotsDict = [[[_deleteStack lastObject] + retain] autorelease];*/ //?? + + [_uniqueStack removeLastObject]; + [_uniqueArrayStack removeLastObject]; + [_deleteStack removeLastObject]; + + [self forgetAllLocks]; + + [_database recordSnapshots: snapshotsDict]; + [_database recordToManySnapshots: toManySnapshotsDict]; + + /* //TODO + if (moified ojects) + call forgetSnapshotForGlobalID: ... + <<<< + DESTROY(_modifiedObjects); + */ + } + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"self=%p _uniqueStack %p=%@", + self, _uniqueStack, _uniqueStack); + + EOFLOGObjectFnStop(); +} + +- (void) _beginTransaction +{ + EOFLOGObjectFnStart(); + + [_uniqueStack addObject: [NSMutableDictionary dictionary]]; + [_uniqueArrayStack addObject: [NSMutableDictionary dictionary]]; + [_deleteStack addObject: [NSMutableDictionary dictionary]]; //TODO: put an object in the dictionary + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"self=%p _uniqueStack %p=%@", + self, _uniqueStack, _uniqueStack); + + EOFLOGObjectFnStop(); +} + +- (EODatabaseChannel*) _obtainOpenChannel +{ + EODatabaseChannel *channel = [self availableChannel]; + + if (![self _openChannelWithLoginPanel: channel]) + { + NSEmitTODO(); + [self notImplemented: _cmd];//TODO + } + + return channel; +} + +- (BOOL) _openChannelWithLoginPanel: (EODatabaseChannel*)databaseChannel +{ + // veridy: LoginPanel ??? + EOAdaptorChannel *adaptorChannel = [databaseChannel adaptorChannel]; + + if (![adaptorChannel isOpen]) //?? + { + [adaptorChannel openChannel]; + } + + return [adaptorChannel isOpen]; +} + +- (void) _forceDisconnect +{ // TODO + NSEmitTODO(); + [self notImplemented: _cmd]; +} + +@end + + +@implementation EODatabaseContext(EOMultiThreaded) + +- (void)lock +{ + [_lock lock]; +} + +- (void)unlock +{ + [_lock unlock]; +} + +@end + +@implementation EODatabaseContext (EODatabaseContextPrivate2) + +- (void) _verifyNoChangesToReadonlyEntity: (EODatabaseOperation*)dbOpe +{ + //TODO + EOEntity *entity = nil; + + EOFLOGObjectFnStart(); + + entity = [dbOpe entity]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"dbOpe=%@", dbOpe); + + if ([entity isReadOnly]) + { + //?? exception I presume + } + else + { + [dbOpe databaseOperator]; //SoWhat + } + + EOFLOGObjectFnStop(); +} + +- (void) _cleanUpAfterSave +{ +//TODO + EOFLOGObjectFnStart(); + + _coordinator = nil; //realesae ? + _editingContext = nil; //realesae ? + + if (_dbOperationsByGlobalID) + { + //Really free it because we don't want to record some db ope (select for exemple). + NSFreeMapTable(_dbOperationsByGlobalID); + _dbOperationsByGlobalID = NULL; + } + + _flags.preparingForSave = NO; +/* +//TODO HERE or in _commitTransaction ? +_numLocked = 0; + _lockedObjects = NSZoneRealloc(NULL, _lockedObjects, + _LOCK_BUFFER*sizeof(id)); + +*/ + + EOFLOGObjectFnStop(); +} + +- (EOGlobalID*)_globalIDForObject: (id)object +{ + EOEditingContext *objectEditingContext = nil; + EOGlobalID *gid = nil; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"object=%p of class %@", + object,[object class]); + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"_editingContext=%p", + _editingContext); + + objectEditingContext = [object editingContext]; + NSAssert1(objectEditingContext, @"No editing context for object %p", object); + + gid = [objectEditingContext globalIDForObject: object]; + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"gid=%@", gid); + + if (!gid) + { + NSEmitTODO(); + NSLog(@"TODO: no GID in EODatabaseContext _globalIDForObject:"); + //TODO exception ? ==> RollbackCh + } + + EOFLOGObjectFnStop(); + + return gid; +} + +- (NSDictionary*)_primaryKeyForObject: (id)object +{ + //NEAR OK + NSDictionary *pk = nil; + EOEntity *entity = nil; + BOOL shouldGeneratePrimaryKey = NO; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"object=%@", object); + + entity = [_database entityForObject: object]; + shouldGeneratePrimaryKey = [self _shouldGeneratePrimaryKeyForEntityName: + [entity name]]; + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"object=%p shouldGeneratePrimaryKey=%d", + object,shouldGeneratePrimaryKey); + + if (shouldGeneratePrimaryKey) + { + BOOL isPKValid = NO; + EOGlobalID *gid = [self _globalIDForObject: object]; //OK + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"gid=%@", gid); +/*NO NSAssert2([gid isKindOfClass:[EOKeyGlobalID class]], + @"%@ is not an EOKeyGlobalID, it's a %@", + gid, + [gid class]); +*/ + pk = [entity primaryKeyForGlobalID: (EOKeyGlobalID*)gid]; //OK + + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"object=%p pk=%@", + object,pk); + + { + NSDictionary *pk2 = nil; + NSArray *pkNames = [entity primaryKeyAttributeNames]; + + pk2 = [self valuesForKeys: pkNames + object: object]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"object=%p pk2=%@", + object,pk2); + + if (pk) + { + //merge pk2 into pk + NSEnumerator *pk2Enum = [pk2 keyEnumerator]; + NSMutableDictionary *realPK = [NSMutableDictionary + dictionaryWithDictionary: pk];//revoir + id key = nil; + + while ((key = [pk2Enum nextObject])) + { + [realPK setObject: [pk2 objectForKey: key] + forKey: key]; + } + + pk = realPK; + } + else + pk=pk2; + } + + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"object=%p pk=%@", + object,pk); + + isPKValid = [entity isPrimaryKeyValidInObject: pk]; + EOFLOGObjectLevelArgs(@"EODatabaseContext",@"object=%p isPKValid=%d", + object,isPKValid); + + if (isPKValid == NO) + { + pk = nil; + + if (_delegateRespondsTo.newPrimaryKey == YES) + pk = [_delegate databaseContext: self + newPrimaryKeyForObject: object + entity: entity]; + + if (!pk) + { + NSArray *pkAttributes = nil; + EOAdaptorChannel *channel = nil; + EOStoredProcedure *nextPKProcedure = nil; + + nextPKProcedure = [entity storedProcedureForOperation: + EONextPrimaryKeyProcedureOperation]; +#if 0 // TODO execute storedProcedure and fetch results; + + if (nextPKProcedure) + [[[self _obtainOpenChannel] adaptorChannel] + executeStoredProcedure: nextPKProcedure + withValues:]; +#endif + + pkAttributes = [entity primaryKeyAttributes]; + + if (pk == nil && [pkAttributes count] == 1) + { + EOAttribute *pkAttr = [pkAttributes objectAtIndex: 0]; + //TODO attr: adaptorValueType //returned EOAdaptorNumberType + //TODO [entity rootParent];//so what + + if (channel == nil) + { + channel = [[self _obtainOpenChannel] adaptorChannel]; + + if ([[channel adaptorContext] + transactionNestingLevel] == 0) + [[channel adaptorContext] beginTransaction]; + + if (_flags.beganTransaction == NO) + { + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"BEGAN TRANSACTION FLAG==>NO"); + _flags.beganTransaction = YES; + } + } + + pk = [channel primaryKeyForNewRowWithEntity: entity]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"** prepare pk %@", pk); + + if (pk == nil && [[pkAttr valueClassName] + isEqual:@"NSData"] == YES) + { + unsigned char data[EOUniqueBinaryKeyLength]; + + [EOTemporaryGlobalID assignGloballyUniqueBytes: data]; + + pk = [NSDictionary dictionaryWithObject: + [NSData dataWithBytes: data + length: + EOUniqueBinaryKeyLength] + forKey: [pkAttr name]]; + } + } + } + + if (!pk) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: cannot generate primary key for object '%@'", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, object]; + } + { + EODatabaseOperation *dbOpe = [self databaseOperationForObject: object]; + NSMutableDictionary *newRow = [dbOpe newRow]; + + [newRow addEntriesFromDictionary: pk];//VERIFY Here we replace previous key + } + } + + EOFLOGObjectFnStop(); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"pk=%@", pk); + NSDebugMLog(@"object %p=%@\npk=%@",object, object, pk); + + return pk; +} + +- (BOOL) _shouldGeneratePrimaryKeyForEntityName: (NSString*)entityName +{ + //OK + BOOL shouldGeneratePK = YES; + + EOFLOGObjectFnStart(); + + if (_nonPrimaryKeyGenerators) + shouldGeneratePK = !NSHashGet(_nonPrimaryKeyGenerators, entityName); + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"shouldGeneratePK for %@: %s", + entityName, + (shouldGeneratePK ? "YES" : "NO")); + NSAssert(![entityName isEqualToString: @"Country"] + || shouldGeneratePK, @"MGVALID: Failed"); + + EOFLOGObjectFnStop(); + + return shouldGeneratePK; +} + +- (void)_buildPrimaryKeyGeneratorListForEditingContext: (EOEditingContext*)context +{ + NSArray *objects[3]; + NSHashTable *processedEntities = NULL; + NSMutableArray *entityToProcess = nil; + int i, which; + + EOFLOGObjectFnStart(); + + if (_nonPrimaryKeyGenerators) + { + NSResetHashTable(_nonPrimaryKeyGenerators); + } + + processedEntities = NSCreateHashTable(NSObjectHashCallBacks, 32); + + objects[0] = [context updatedObjects]; + objects[1] = [context insertedObjects]; + objects[2] = [context deletedObjects]; + + for (which = 0; which < 3; which++) + { + int count = [objects[which] count]; + + for (i = 0; i < count; i++) + { + id object = [objects[which] objectAtIndex: i]; + EOEntity *entity = [_database entityForObject: object]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"add entity to process: %@", [entity name]); + + if (entityToProcess) + [entityToProcess addObject: entity]; + else + entityToProcess = [NSMutableArray arrayWithObject: entity]; + } + } + + while ([entityToProcess count]) + { + EOEntity *entity = [entityToProcess lastObject]; + + EOFLOGObjectLevelArgs(@"EODatabaseContext", @"test entity: %@", + [entity name]); + + [entityToProcess removeLastObject]; + + if (!NSHashInsertIfAbsent(processedEntities, entity)) //Already processed ? + { + NSArray *relationships = nil; + int iRelationship = 0; + int relationshipsCount = 0; + + relationships = [entity relationships]; + iRelationship = 0; + relationshipsCount = [relationships count]; + + for (iRelationship = 0; + iRelationship < relationshipsCount; + iRelationship++) + { + EORelationship *relationship = [relationships objectAtIndex: + iRelationship]; + + if ([relationship propagatesPrimaryKey]) + { + EOEntity *destinationEntity = [relationship + destinationEntity]; + + if (destinationEntity) + { + EOFLOGObjectLevelArgs(@"EODatabaseContext", + @"destination entity: %@ No PrimaryKey Generation [Relatiuonship = %@]", + [destinationEntity name], + [relationship name]); + + if (!_nonPrimaryKeyGenerators) + _nonPrimaryKeyGenerators = NSCreateHashTable(NSObjectHashCallBacks, 32); + + NSHashInsertIfAbsent(_nonPrimaryKeyGenerators, [destinationEntity name]); + [entityToProcess addObject: destinationEntity]; + } + } + } + } + } + + EOFLOGObjectFnStop(); + + NSFreeHashTable(processedEntities); +} + +/** Returns a dictionary containing a snapshot of object that reflects its committed values (last values putted in the database; i.e. values before changes were made on the object). +It is updated after commiting new values. +If the object has been just inserted, the dictionary is empty. +**/ +- (NSDictionary*)_currentCommittedSnapshotForObject: (id)object +{ + NSDictionary *snapshot = nil; + EOGlobalID *gid = nil; + EODatabaseOperation *dbOpe = nil; + EODatabaseOperator dbOperator = (EODatabaseOperator)0; + + EOFLOGObjectFnStart(); + + gid = [_editingContext globalIDForObject: object]; + dbOpe = [self databaseOperationForGlobalID: gid]; //I'm not sure. Retrieve it directly ? + dbOperator = [dbOpe databaseOperator]; + + switch (dbOperator) + { + case EODatabaseUpdateOperator: + snapshot = [_editingContext committedSnapshotForObject: object];//OK + break; + + case EODatabaseInsertOperator: + snapshot = [NSDictionary dictionary]; + break; + +//TODO +/* else + snapshot=XX;//TODO +*/ + case EODatabaseDeleteOperator: + break; + + case EODatabaseNothingOperator: + break; + } + + EOFLOGObjectFnStop(); + + return snapshot; +} + + +- (void) _assertValidStateWithSelector: (SEL)sel +{ +// [self notImplemented:_cmd]; //TODO +} + +- (id) _addDatabaseContextStateToException: (id)param0 +{ + NSEmitTODO(); + return [self notImplemented: _cmd]; //TODO +} + +- (id) _databaseContextState +{ + NSEmitTODO(); + return [self notImplemented: _cmd]; //TODO +} + +@end diff --git a/EOAccess/EODatabaseContextPriv.h b/EOAccess/EODatabaseContextPriv.h new file mode 100644 index 0000000..47fd4e4 --- /dev/null +++ b/EOAccess/EODatabaseContextPriv.h @@ -0,0 +1,70 @@ +/* + EODatabaseContextPriv.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: July 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EODatabaseContextPriv_h__ +#define __EODatabaseContextPriv_h__ + +@class EOAccessFaultHandler; +@class EOAccessArrayFaultHandler; + + +@interface EODatabaseContext (EODatabaseContextPrivate) + +- (void) _fireArrayFault: (id)object; +- (void) _fireFault: (id)object; +- (void) _addBatchForGlobalID: (EOKeyGlobalID *)globalID + fault: (EOFault *)fault; +- (void) _removeBatchForGlobalID: (EOKeyGlobalID *)globalID + fault: (EOFault *)fault; +- (void) _addToManyBatchForSourceGlobalID: (EOKeyGlobalID *)globalID + relationshipName: (NSString *)relationshipName + fault: (EOFault *)fault; + +/*- (void)_batchToOne: (id)fault + withHandler: (EOAccessFaultHandler *)handler; +- (void)_batchToMany: (id)fault +withHandler: (EOAccessArrayFaultHandler *)handler;*/ + +@end + + +@interface EODatabaseContext (EODatabaseContextPrivate2) + +- (void) _verifyNoChangesToReadonlyEntity: (EODatabaseOperation*)dbOpe; +- (EOGlobalID*) _globalIDForObject: (id)object; +- (id) _primaryKeyForObject: (id)object; +- (id) _currentCommittedSnapshotForObject: (id)object; +- (id) _addDatabaseContextStateToException: (id)param0; +- (id) _databaseContextState; +- (void) _cleanUpAfterSave; +- (void) _assertValidStateWithSelector: (SEL)sel; +- (BOOL) _shouldGeneratePrimaryKeyForEntityName: (NSString*)entityName; +- (void) _buildPrimaryKeyGeneratorListForEditingContext: (EOEditingContext*)context; + +@end + + +#endif /* __EODatabaseContextPriv_h__ */ diff --git a/EOAccess/EODatabaseDataSource.h b/EOAccess/EODatabaseDataSource.h new file mode 100644 index 0000000..6769067 --- /dev/null +++ b/EOAccess/EODatabaseDataSource.h @@ -0,0 +1,67 @@ +/* + EODatabaseDataSource.m + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: July 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#import + +@class EOEntity; +@class EODatabaseContext; + + +@interface EODatabaseDataSource : EODataSource +{ + EOEditingContext *_editingContext; + EOFetchSpecification *_fetchSpecification; + EOQualifier *_auxiliaryQualifier; + NSDictionary *_bindings; + + struct { + unsigned int fetchEnabled:1; + unsigned int _reserved:31; + } _flags; +} + +- initWithEditingContext: (EOEditingContext *)anEditingContext + entityName: (NSString *)anEntityName; +- initWithEditingContext: (EOEditingContext *)editingContext + entityName: (NSString *)entityName + fetchSpecificationName: (NSString *)fetchName; + +- (EOEntity *)entity; + +- (EODatabaseContext *)databaseContext; + +- (void)setFetchSpecification: (EOFetchSpecification *)fetchSpecification; +- (EOFetchSpecification *)fetchSpecification; + +- (void)setAuxiliaryQualifier: (EOQualifier *)newQualifier; +- (EOQualifier *)auxiliaryQualifier; + +- (EOFetchSpecification *)fetchSpecificationForFetch; + +- (void)setFetchEnabled: (BOOL)yn; +- (BOOL)isFetchEnabled; + +@end diff --git a/EOAccess/EODatabaseDataSource.m b/EOAccess/EODatabaseDataSource.m new file mode 100644 index 0000000..d52b15d --- /dev/null +++ b/EOAccess/EODatabaseDataSource.m @@ -0,0 +1,418 @@ +/** + EODatabaseDataSource.m EODatabaseDataSource Class + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: July 2000 + + Author: Manuel Guesdon + Date: December 2001 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import +#import + +#import +#import +#import +#import +#import +#import +#import + +@implementation EODatabaseDataSource + +- initWithEditingContext: (EOEditingContext *)editingContext + entityName: (NSString *)entityName +{ + return [self initWithEditingContext: editingContext + entityName: entityName + fetchSpecificationName: nil]; +} + +- initWithEditingContext: (EOEditingContext *)editingContext + entityName: (NSString *)entityName + fetchSpecificationName: (NSString *)fetchName +{ + NSArray *stores; + EODatabaseContext *store = nil; + NSEnumerator *storeEnum; + EOModel *model; + EOEntity *entity = nil; + id rootStore; + + if ((self = [super init])) + { + ASSIGN(_editingContext, editingContext); + rootStore = [_editingContext rootObjectStore]; + + if ([rootStore isKindOfClass: [EOObjectStoreCoordinator class]] == YES) + { + stores = [rootStore cooperatingObjectStores]; + + storeEnum = [stores objectEnumerator]; + while ((store = [storeEnum nextObject])) + { + if ([store isKindOfClass: [EODatabaseContext class]] == YES) + { + if ((entity = [[store database] entityNamed: entityName])) + break; + } + } + + if (store == nil) + { + entity = [[EOModelGroup defaultGroup] entityNamed: entityName]; + model = [entity model]; + + store = [EODatabaseContext databaseContextWithDatabase: + [EODatabase databaseWithModel: + model]]; + + [rootStore addCooperatingObjectStore: store]; + } + } + else if ([rootStore isKindOfClass: [EODatabaseContext class]] == YES) + { + if ((entity = [[store database] entityNamed: entityName]) == nil) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: editingContext (%@) cannot handler entity named '%@'", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + editingContext, + entityName]; + } + else + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: editingContext (%@) cannot handler entity named '%@'", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + editingContext, + entityName]; + + ASSIGN(_fetchSpecification, [entity fetchSpecificationNamed:fetchName]); + } + + return self; +} + +- (void)dealloc +{ + DESTROY(_bindings); + DESTROY(_auxiliaryQualifier); + DESTROY(_fetchSpecification); + DESTROY(_editingContext); + + [super dealloc]; +} + +- (NSString *)description +{ + return [NSString stringWithFormat: + @"<%s %p : entity name=%@ editingContext=%p fetchSpecification=%@>", + object_get_class_name(self), + (void *)self, + [[self entity]name], + _editingContext, + _fetchSpecification]; +} + +- (EOEntity *)entity +{ + return [[[self databaseContext] database] + entityNamed: [_fetchSpecification entityName]]; +} + +- (EODatabaseContext *)databaseContext +{ + NSArray *stores = nil; + EODatabaseContext *store = nil; + NSEnumerator *storeEnum = nil; + NSString *entityName = nil; + id rootStore = nil; + + entityName = [_fetchSpecification entityName]; + + rootStore = [_editingContext rootObjectStore]; + if ([rootStore isKindOfClass: [EOObjectStoreCoordinator class]] == YES) + { + stores = [rootStore cooperatingObjectStores]; + + storeEnum = [stores objectEnumerator]; + while ((store = [storeEnum nextObject])) + { + if ([store isKindOfClass: [EODatabaseContext class]] == YES) + { + if ([[store database] entityNamed: entityName]) + break; + } + } + } + else if ([rootStore isKindOfClass: [EODatabaseContext class]] == YES) + { + if ([[store database] entityNamed: entityName]) + store = rootStore; + } + + return store; +} + +- (void)setFetchSpecification: (EOFetchSpecification *)fetchSpecification +{ + ASSIGN(_fetchSpecification, fetchSpecification); +} + +- (EOFetchSpecification *)fetchSpecification +{ + return _fetchSpecification; +} + +- (void)setAuxiliaryQualifier: (EOQualifier *)qualifier +{ + ASSIGN(_auxiliaryQualifier, qualifier);//OK +} + +- (EOQualifier *)auxiliaryQualifier +{ + return _auxiliaryQualifier; +} + +- (EOFetchSpecification *)fetchSpecificationForFetch +{ + EOFetchSpecification *fetch = nil; + EOQualifier *qualifier = nil; + + EOFLOGObjectLevelArgs(@"EODataSource", @"_auxiliaryQualifier=%@", + _auxiliaryQualifier); + EOFLOGObjectLevelArgs(@"EODataSource", @"_bindings=%@", _bindings); + EOFLOGObjectLevelArgs(@"EODataSource", @"_fetchSpecification=%@", + _fetchSpecification); + + qualifier = [_auxiliaryQualifier + qualifierWithBindings: _bindings + requiresAllVariables: [_fetchSpecification + requiresAllQualifierBindingVariables]]; //ret same ? + + EOFLOGObjectLevelArgs(@"EODataSource", @"qualifier=%@", qualifier); + +//call _fetchSpecification qualifier //ret nil //TODO + fetch = [[_fetchSpecification copy] autorelease]; + + EOFLOGObjectLevelArgs(@"EODataSource", @"fetch=%@", fetch); + + [fetch setQualifier:qualifier]; +/* + fetch = [_fetchSpecification copy]; + [fetch setQualifier:[[[EOAndQualifier alloc] + initWithQualifiers:[fetch qualifier], + _auxiliaryQualifier, nil] autorelease]]; +*/ + + EOFLOGObjectLevelArgs(@"EODataSource", @"fetch=%@", fetch); + + return fetch; +} + +- (void)setFetchEnabled: (BOOL)flag +{ + _flags.fetchEnabled = flag; +} + +- (BOOL)isFetchEnabled +{ + return _flags.fetchEnabled; +} + +- (EODataSource *)dataSourceQualifiedByKey: (NSString *)detailKey +{ + return [EODetailDataSource detailDataSourceWithMasterDataSource: self + detailKey: detailKey]; +} + +- (void)insertObject: object +{ + [_editingContext insertObject: object]; +} + +- (void)deleteObject: object +{ + [_editingContext deleteObject: object]; +} + +- (NSArray *)fetchObjects +{ + NSArray *objects = nil; + + EOFLOGObjectLevelArgs(@"EODataSource", @"_editingContext=%@", + _editingContext); + NSAssert(_editingContext, @"No Editing Context"); + +//call [self isFetchEnabled]; + NS_DURING//For trace purpose + { + objects = [_editingContext objectsWithFetchSpecification: + [self fetchSpecificationForFetch]];//OK + } + NS_HANDLER + { + NSLog(@"%@ (%@)", localException, [localException reason]); + NSDebugMLog(@"%@ (%@)", localException, [localException reason]); + [localException raise]; + } + NS_ENDHANDLER; + + EOFLOGObjectLevelArgs(@"EODataSource", @"objects=%p", objects); + EOFLOGObjectLevelArgs(@"EODataSource", @"objects count=%d", [objects count]); + EOFLOGObjectLevelArgs(@"EODataSource", @"objects=%@", objects); + + return objects; +} + +- (EOClassDescription *)classDescriptionForObjects +{ + return [[self entity] classDescriptionForInstances]; +} + +- (NSArray *)qualifierBindingKeys +{ + return [_bindings allKeys]; // TODO resolve all bindings question +} + +- (void)setQualifierBindings: (NSDictionary *)bindings +{ + ASSIGN(_bindings, bindings); +} + +- (NSDictionary *)qualifierBindings +{ + return _bindings; +} + +- (id)initWithCoder: (NSCoder *)coder +{ + self = [super init]; + + ASSIGN(_editingContext, [coder decodeObject]); + ASSIGN(_fetchSpecification, [coder decodeObject]); + ASSIGN(_auxiliaryQualifier, [coder decodeObject]); + ASSIGN(_bindings, [coder decodeObject]); + + // TODO flags + + return self; +} + +- (void)encodeWithCoder: (NSCoder *)coder +{ + [coder encodeObject:_editingContext]; + [coder encodeObject:_fetchSpecification]; + [coder encodeObject:_auxiliaryQualifier]; + [coder encodeObject:_bindings]; + + // TODO flags +} + +- (id) initWithKeyValueUnarchiver: (EOKeyValueUnarchiver *)unarchiver +{ + NSString *entityName = nil; + EOFetchSpecification *fetchSpecification = nil; + EOQualifier *auxiliaryQualifier = nil; + EOEditingContext *editingContext = nil; + NSString *fetchSpecificationName = nil; + + EOFLOGObjectFnStart(); + + entityName = [unarchiver decodeObjectForKey: @"entityName"]; + EOFLOGObjectLevelArgs(@"EODataSource",@"entityName=%@",entityName); + + fetchSpecification = [unarchiver decodeObjectForKey: @"fetchSpecification"]; + EOFLOGObjectLevelArgs(@"EODataSource", @"fetchSpecification=%@", + fetchSpecification); + + auxiliaryQualifier = [unarchiver decodeObjectForKey: @"auxiliaryQualifier"]; + EOFLOGObjectLevelArgs(@"EODataSource", @"auxiliaryQualifier=%@", + auxiliaryQualifier); + + editingContext = [unarchiver decodeObjectReferenceForKey: @"editingContext"]; + EOFLOGObjectLevelArgs(@"EODataSource", @"editingContext=%@", editingContext); + + fetchSpecificationName = [unarchiver decodeObjectForKey: + @"fetchSpecificationName"]; + EOFLOGObjectLevelArgs(@"EODataSource", @"fetchSpecificationName=%@", + fetchSpecificationName); + + if (!entityName) + { + entityName = [fetchSpecification entityName]; + EOFLOGObjectLevelArgs(@"EODataSource", @"entityName=%@", entityName); + } + + if ((self = [self _partialInitWithEditingContext: editingContext + entityName: entityName + fetchSpecificationName: fetchSpecificationName])) + { + [self setFetchSpecification: fetchSpecification]; + } + + return self; +} + +- (void) encodeWithKeyValueArchiver: (EOKeyValueUnarchiver *)archiver +{ + [self notImplemented: _cmd]; +} + +- (id)_partialInitWithEditingContext: (EOEditingContext*)editingContext + entityName: (NSString*)entityName + fetchSpecificationName: (NSString*)fetchSpecificationName +{ + if ((self = [self initWithEditingContext: editingContext + entityName: entityName + fetchSpecificationName: nil])) + { + //turbocat ASSIGN(_editingContext,editingContext); + ASSIGN(_fetchSpecification, [EOFetchSpecification new]); + [_fetchSpecification setEntityName: entityName]; + } + + return self; +} + +- (EOEditingContext*)editingContext +{ + return _editingContext; +} + +@end diff --git a/EOAccess/EODatabaseOperation.h b/EOAccess/EODatabaseOperation.h new file mode 100644 index 0000000..8212998 --- /dev/null +++ b/EOAccess/EODatabaseOperation.h @@ -0,0 +1,180 @@ +/* + EODatabaseOperation.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EODatabaseOperation_h__ +#define __EODatabaseOperation_h__ + +#import + + +@class EOStoredProcedure; +@class EOEntity; + + +typedef enum { + EOAdaptorUndefinedOperator = 0, + EOAdaptorLockOperator, + EOAdaptorInsertOperator, + EOAdaptorUpdateOperator, + EOAdaptorDeleteOperator, + EOAdaptorStoredProcedureOperator +} EOAdaptorOperator; + +/** +EOAdaptorOperation represent an adaptor 'elementaty' operation. +Instance objects are created by EODatabaseOperation +**/ +@interface EOAdaptorOperation : NSObject +{ + EOAdaptorOperator _adaptorOperator; /** Database Adaptor **/ + EOEntity *_entity; /** Main concerned entity **/ + EOQualifier *_qualifier; /** qualifier **/ + NSDictionary *_changedValues; /** dictionary of changed fields/values **/ + NSArray *_attributes; + EOStoredProcedure *_storedProcedure; /** Stored Procedure **/ + NSException *_exception; +} + ++ (EOAdaptorOperation *)adaptorOperationWithEntity: (EOEntity *)entity; + +/** Init the instance with the main concerned entity **/ +- (id) initWithEntity: (EOEntity *)entity; + +/** returns adaptor operator **/ +- (EOAdaptorOperator)adaptorOperator; + +/** set adaptor operator **/ +- (void)setAdaptorOperator: (EOAdaptorOperator)adaptorOperator; + +/** returns entity **/ +- (EOEntity *)entity; + +/** returns qualifier **/ +- (EOQualifier *)qualifier; + +/** set Qualifier **/ +- (void)setQualifier: (EOQualifier *)qualifier; + +/** returns dictionary of changed values **/ +- (NSDictionary *)changedValues; + +/** set dictionary of changed values **/ +- (void)setChangedValues: (NSDictionary *)changedValues; + + +- (NSArray *)attributes; +- (void)setAttributes: (NSArray *)attributes; + +- (EOStoredProcedure *)storedProcedure; +- (void)setStoredProcedure: (EOStoredProcedure *)storedProcedure; + +- (NSException *)exception; +- (void)setException: (NSException *)exception; + +/** compare 2 adaptor operations **/ +- (NSComparisonResult)compareAdaptorOperation: (EOAdaptorOperation *)adaptorOp; + +@end + +typedef enum { + EODatabaseNothingOperator = 0, + EODatabaseInsertOperator, + EODatabaseUpdateOperator, + EODatabaseDeleteOperator +} EODatabaseOperator; + +/** +EODatabaseOperation represent a database high level operation on an object (record) +It creates EOAdaptorOperations. +You generally don't need to create such objects by yourself. They are created by EOEditingContext +**/ +@interface EODatabaseOperation : NSObject +{ + EODatabaseOperator _databaseOperator; //** Database Operator **/ + NSMutableDictionary *_newRow; //** New Row (new state of the object) **/ + EOGlobalID *_globalID; /** global ID of the object **/ + EOEntity *_entity; /** entity **/ + NSMutableArray *_adaptorOps; /** EOAdaptorOperations generated to perfor this DatabaseOperation **/ + id _object; /** object (record) **/ + NSDictionary *_dbSnapshot; /** The last known database values for the object (i.e. values from last fetch or last commited operation) **/ + NSMutableDictionary *_toManySnapshots; /** **/ +} + ++ (EODatabaseOperation*)databaseOperationWithGlobalID: (EOGlobalID *)globalID + object: (id)object + entity: (EOEntity *)entity; + +- (id)initWithGlobalID: (EOGlobalID *)globalID + object: (id)object + entity: (EOEntity *)entity; + +/** Returns the database snapshot for the object. +The snapshot contains the last known database values for the object. +If the object has just been inserted (i.e. not yet in database), the returned dictionary is empty +**/ +- (NSDictionary *)dbSnapshot; + +/** sets the snapshot for the object (should be empty if the object has just been inserted into an EOEditingContext **/ +- (void)setDBSnapshot: (NSDictionary *)dbSnapshot; + +/** Returns a dictionary with (new) values (properties+primary keys...) of the object. +The newRow dictionary is created when creating the database operation (in EODatabaseChannel -databaseOperationForObject: for exemple). Values come from object state in database and overrides by changes made on the object +**/ +- (NSMutableDictionary *)newRow; +- (void)setNewRow:(NSMutableDictionary *)newRow; + +- (EOGlobalID *)globalID; + +- (id)object; + +- (EOEntity *)entity; + +- (EODatabaseOperator)databaseOperator; +- (void)setDatabaseOperator: (EODatabaseOperator)dbOp; + +- (NSDictionary *)rowDiffs; + +- (NSDictionary *)rowDiffsForAttributes: (NSArray *)attributes; + +- (NSDictionary *)primaryKeyDiffs; + +/** returns array of EOAdaptorOperations to perform **/ +- (NSArray *)adaptorOperations; + +/** adds an Adaptor Operation +Raises an exception if adaptorOperation is nil +**/ +- (void)addAdaptorOperation: (EOAdaptorOperation *)adaptorOperation; + +/** removes an Adaptor Operation **/ +- (void)removeAdaptorOperation: (EOAdaptorOperation *)adaptorOperation; + +- (void)recordToManySnapshot: (NSArray *)gids relationshipName:(NSString *)name; +- (NSDictionary *)toManySnapshots; + +@end + +#endif /* __EODatabaseOperation_h__ */ diff --git a/EOAccess/EODatabaseOperation.m b/EOAccess/EODatabaseOperation.m new file mode 100644 index 0000000..7be1642 --- /dev/null +++ b/EOAccess/EODatabaseOperation.m @@ -0,0 +1,351 @@ +/** + EOAdaptorOperation.m EOAdaptorOperation Class + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import + +#import + +#import +#import +#import +#import + +@implementation EODatabaseOperation + ++ (EODatabaseOperation *)databaseOperationWithGlobalID: (EOGlobalID *)globalID + object: (id)object + entity: (EOEntity *)entity +{ + return [[[self alloc] initWithGlobalID: globalID + object: object + entity: entity] autorelease]; +} + +- (id) initWithGlobalID: (EOGlobalID *)globalID + object: (id)object + entity: (EOEntity *)entity +{ + if ((self = [super init])) + { + ASSIGN(_object, object); + ASSIGN(_globalID, globalID); + ASSIGN(_entity, entity); + + //_newRow = [NSMutableDictionary new];//still nil + + //_toManySnapshots = [NSMutableDictionary new];//TODO no: still nil + } + + return self; +} + +- (void)dealloc +{ + DESTROY(_newRow); + DESTROY(_globalID); + DESTROY(_entity); + DESTROY(_adaptorOps); + DESTROY(_object); + DESTROY(_dbSnapshot); + DESTROY(_toManySnapshots); + + [super dealloc]; +} + +- (NSDictionary *)dbSnapshot +{ + EOFLOGObjectFnStart(); + + NSDebugMLLog(@"gsdb", @"dbOpe %@ snapshot %p=%@", self, _dbSnapshot, _dbSnapshot); + + EOFLOGObjectFnStop(); + + return _dbSnapshot; +} + +- (void)setDBSnapshot: (NSDictionary *)dbSnapshot +{ + EOFLOGObjectFnStart(); + + ASSIGN(_dbSnapshot, dbSnapshot); + + NSDebugMLLog(@"gsdb", @"dbOpe %@ snapshot %p=%@", self, _dbSnapshot, _dbSnapshot); + + if (dbSnapshot) + [_newRow addEntriesFromDictionary: dbSnapshot]; + + NSDebugMLLog(@"gsdb", @"dbOpe %@", self); + + EOFLOGObjectFnStop(); +} + +- (NSMutableDictionary *)newRow +{ + return _newRow; +} + +- (void)setNewRow: (NSMutableDictionary *)newRow +{ + ASSIGN(_newRow, newRow); +} + +- (EOGlobalID *)globalID +{ + return _globalID; +} + +- (id)object +{ + return _object; +} + +- (EOEntity *)entity +{ + return _entity; +} + +- (EODatabaseOperator)databaseOperator +{ + return _databaseOperator; +} + +- (void)setDatabaseOperator: (EODatabaseOperator)dbOpe +{ + BOOL setOpe = YES; + + //Don't set Update if it's alreay insert + if (dbOpe == EODatabaseUpdateOperator) + { + if (_databaseOperator==EODatabaseInsertOperator + || _databaseOperator==EODatabaseDeleteOperator) + setOpe=NO; + } + + if (setOpe) + _databaseOperator = dbOpe; +} + +- (NSDictionary *)rowDiffs +{ + //OK + NSMutableDictionary *row = nil; + NSEnumerator *newRowEnum = nil; + NSString *key = nil; + + EOFLOGObjectFnStart(); + + NSDebugMLLog(@"gsdb", @"self %p=%@", self, self); + + newRowEnum= [_newRow keyEnumerator]; + + while ((key = [newRowEnum nextObject])) + { + if (![_entity anyRelationshipNamed: key]) //Don't care about relationships + { + id value = [_newRow objectForKey: key]; + + if ([value isEqual: [_dbSnapshot objectForKey: key]] == NO) + { + if (!row) + row = (NSMutableDictionary*)[NSMutableDictionary dictionary]; + + [row setObject: value + forKey: key]; + } + } + } + + NSDebugMLLog(@"gsdb", @"diff row %p=%@", row, row); + + EOFLOGObjectFnStop(); + + return row; +} + +- (NSDictionary*)rowDiffsForAttributes: (NSArray*)attributes +{ + //OK + NSMutableDictionary *row = nil; + EOAttribute *attr = nil; + NSEnumerator *attrsEnum = nil; + + EOFLOGObjectFnStart(); + + NSDebugMLLog(@"gsdb", @"self %p=%@", self, self); + + attrsEnum = [attributes objectEnumerator]; + while ((attr = [attrsEnum nextObject])) + { + NSString *name = [attr name]; + NSString *snapname = [_entity snapshotKeyForAttributeName: name]; + id value = [_newRow objectForKey: name]; + + if (value && [value isEqual: [_dbSnapshot objectForKey: snapname]] == NO) + { + if (!row) + row = (NSMutableDictionary*)[NSMutableDictionary dictionary]; + + [row setObject: value + forKey: name]; + } + } + + NSDebugMLLog(@"gsdb", @"diff row %p=%@", row, row); + + EOFLOGObjectFnStop(); + + return row; +} + +- (NSDictionary *)primaryKeyDiffs +{ + //OK + NSDictionary *row = nil; + + if (_databaseOperator == EODatabaseUpdateOperator) + { + NSArray *pkAttributes = [_entity primaryKeyAttributes]; + + row = [self rowDiffsForAttributes: pkAttributes]; + } + + return row; +} + +- (NSArray *)adaptorOperations +{ + return _adaptorOps; +} + +- (void)addAdaptorOperation: (EOAdaptorOperation *)adaptorOperation +{ + //OK + if (!_adaptorOps) + _adaptorOps = [NSMutableArray new]; + + if (!adaptorOperation) + { + //TODO raise exception + } + else + [_adaptorOps addObject: adaptorOperation]; +} + +- (void)removeAdaptorOperation: (EOAdaptorOperation *)adaptorOperation +{ + [_adaptorOps removeObject: adaptorOperation]; +} + +- (void)recordToManySnapshot: (NSArray *)gids + relationshipName: (NSString *)name +{ + //OK ?? + if (_toManySnapshots) + [_toManySnapshots setObject: gids + forKey: name];//TODO VERIFY + else + { + _toManySnapshots = [NSMutableDictionary dictionaryWithObject: gids + forKey: name]; + + RETAIN(_toManySnapshots); + } +} + +- (NSDictionary *)toManySnapshots +{ + return _toManySnapshots; +} + +- (NSString *)description +{ + //TODO revoir + NSString *operatorString = nil; + NSString *desc = nil; + + EOFLOGObjectFnStart(); + + switch (_databaseOperator) + { + case EODatabaseNothingOperator: + operatorString = @"EODatabaseNothingOperator"; + break; + + case EODatabaseInsertOperator: + operatorString = @"EODatabaseInsertOperator"; + break; + + case EODatabaseUpdateOperator: + operatorString = @"EODatabaseUpdateOperator"; + break; + + case EODatabaseDeleteOperator: + operatorString = @"EODatabaseDeleteOperator"; + break; + + default: + operatorString = @"Unknwon"; + break; + } + + desc = [NSString stringWithFormat: @"<%s %p : operator: %@ entity: %@ globalID:%@\nnewRow %p: %@\nobject %p: %@\ndbSnapshot %p: %@>", + object_get_class_name(self), + (void*)self, + operatorString, + [_entity name], + _globalID, + _newRow, + _newRow, + _object, + _object, + _dbSnapshot, + _dbSnapshot]; + + EOFLOGObjectFnStop(); + + return desc; +} + +@end + +//Mirko +@implementation EODatabaseOperation (private) + +- (void)_setGlobalID: (EOGlobalID *)globalID +{ + ASSIGN(_globalID, globalID); +} + +@end diff --git a/EOAccess/EODatabaseOperationPriv.h b/EOAccess/EODatabaseOperationPriv.h new file mode 100644 index 0000000..f270ecf --- /dev/null +++ b/EOAccess/EODatabaseOperationPriv.h @@ -0,0 +1,37 @@ +/* + EODatabaseOperationPriv.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: July 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EODatabaseOperationPriv_h__ +#define __EODatabaseOperationPriv_h__ + + +@interface EODatabaseOperation (private) + +- (void)_setGlobalID: (EOGlobalID *)globalID; + +@end + +#endif /* __EODatabaseOperationPriv_h__ */ diff --git a/EOAccess/EOEntity.h b/EOAccess/EOEntity.h new file mode 100644 index 0000000..6efc828 --- /dev/null +++ b/EOAccess/EOEntity.h @@ -0,0 +1,373 @@ +/* + EOEntity.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOEntity_h__ +#define __EOEntity_h__ + +#import +#import +#import +#import +#import + +#import +#import + + +@class EOModel; +@class EOAttribute; +@class EOQualifier; +@class EORelationship; +@class EOEntity; +@class EOStoredProcedure; +@class EOKeyGlobalID; + + +@class EOFetchSpecification; +@class EOGlobalID; + +@class EOMutableKnownKeyDictionary; +@class EOMKKDInitializer; +@class EOMKKDSubsetMapping; + +@interface EOEntity : GCObject +{ + NSString *_name; + NSString *_className; + NSString *_externalName; + NSString *_externalQuery; + NSDictionary *_userInfo; + NSString* _docComment; + NSDictionary * _internalInfo; + EOQualifier *_restrictingQualifier; + NSMutableDictionary *_fetchSpecificationDictionary; + NSArray *_fetchSpecificationNames; + NSMutableDictionary *_storedProcedures; + + NSArray *_classPropertyNames; + NSArray *_primaryKeyAttributeNames; + NSArray *_classPropertyAttributeNames; + NSArray *_classPropertyToOneRelationshipNames; + NSArray *_classPropertyToManyRelationshipNames; + EOClassDescription *_classDescription; + NSMutableArray *_hiddenRelationships; + unsigned int _batchCount; + EOMKKDInitializer* _adaptorDictionaryInitializer; + EOMKKDInitializer* _snapshotDictionaryInitializer; + EOMKKDInitializer* _primaryKeyDictionaryInitializer; + EOMKKDInitializer* _propertyDictionaryInitializer; + EOMKKDSubsetMapping* _snapshotToAdaptorRowSubsetMapping; + + Class _classForInstances; + + /* Garbage collectable objects */ + EOModel *_model; + GCMutableArray *_attributes; + GCMutableDictionary *_attributesByName; + GCMutableArray *_relationships; + GCMutableDictionary *_relationshipsByName; // name/EORelationship + GCMutableArray *_primaryKeyAttributes; + GCMutableArray *_classProperties; // EOAttribute/EORelationship + GCMutableArray *_attributesUsedForLocking; + GCMutableArray *_attributesToFetch; + GCMutableArray *_attributesToSave; + GCMutableArray *_propertiesToFault; + GCArray* _dbSnapshotKeys; + + GCMutableArray *_subEntities; + EOEntity *_parent; + + struct { + unsigned int attributesIsLazy:1; + unsigned int relationshipsIsLazy:1; + unsigned int classPropertiesIsLazy:1; + unsigned int primaryKeyAttributesIsLazy:1; + unsigned int attributesUsedForLockingIsLazy:1; + + unsigned int isReadOnly:1; + unsigned int isAbstractEntity:1; + unsigned int updating:1; + unsigned int cachesObjects:1; + + unsigned int createsMutableObjects:1; + + unsigned int extraRefCount:22; + } _flags; +} + +/** returns an autoreleased entity **/ ++ (EOEntity *)entity; + +/** returns an autoreleased entity owned by onwer and built from propertyList **/ ++ (EOEntity *)entityWithPropertyList: (NSDictionary *)propertyList + owner: (id)owner; +- (NSString *)description; + +/* Accessing the name */ +- (NSString*)name; + +/* Accessing the model */ +- (EOModel*)model; + +/* Accessing external information */ +- (NSString*)externalName; + +/* Accessing the external query */ +- (NSString*)externalQuery; + +/* Getting the qualifier */ +- (EOQualifier *)restrictingQualifier; + +- (BOOL)isQualifierForPrimaryKey: (EOQualifier *)qualifier; +- (EOQualifier *)qualifierForPrimaryKey: (NSDictionary *)row; + +/* Accessing read-only status */ +- (BOOL)isReadOnly; + +- (BOOL)cachesObjects; + +/* Accessing the enterprise object class */ +- (NSString*)className; + +/* Accessing attributes */ +- (EOAttribute *)attributeNamed: (NSString *)attributeName; +- (EOAttribute *)anyAttributeNamed: (NSString *)relationshipName; +- (NSArray *)attributes; + +/* Accessing relationships */ +- (EORelationship *)relationshipNamed: (NSString *)relationshipName; +- (EORelationship *)anyRelationshipNamed: (NSString *)relationshipName; +- (NSArray *)relationships; + +/* Accessing class properties */ +- (NSArray *)classProperties; +- (NSArray *)classPropertyNames; + +- (NSArray *)fetchSpecificationNames; +- (EOFetchSpecification *)fetchSpecificationNamed: (NSString *)fetchSpecName; + +/* Accessing primary key attributes */ +- (NSArray *)primaryKeyAttributes; +- (NSArray *)primaryKeyAttributeNames; + +/* Accessing locking attributes */ +- (NSArray *)attributesUsedForLocking; +- (NSArray *)attributesToFetch; + +/* Getting primary keys and snapshot for row */ +- (NSDictionary *)primaryKeyForRow: (NSDictionary *)row; +- (BOOL)isValidAttributeUsedForLocking: (EOAttribute *)anAttribute; +- (BOOL)isValidPrimaryKeyAttribute: (EOAttribute *)anAttribute; +- (BOOL)isPrimaryKeyValidInObject: (id)object; +- (BOOL)isValidClassProperty: aProp; + +/** Accessing the user dictionary **/ +- (NSDictionary *)userInfo; + +/** Accessing the documentation **/ +- (NSString *)docComment; + +- (NSArray *)subEntities; +- (EOEntity *)parentEntity; +- (BOOL)isAbstractEntity; + + +- (unsigned int)maxNumberOfInstancesToBatchFetch; +- (BOOL)isPrototypeEntity; + +@end + +@interface EOEntity (EOKeyGlobalID) +- (EOGlobalID *)globalIDForRow: (NSDictionary *)row; +- (id) globalIDForRow: (NSDictionary*)row + isFinal: (BOOL)isFinal; +- (NSDictionary *)primaryKeyForGlobalID: (EOKeyGlobalID *)gid; +- (Class)classForObjectWithGlobalID: (EOKeyGlobalID*)globalID; +@end + + +@interface EOEntity (EOEntityEditing) + +- (BOOL)setClassProperties: (NSArray*)properties; +- (BOOL)setPrimaryKeyAttributes: (NSArray*)keys; +- (BOOL)setAttributesUsedForLocking: (NSArray*)attributes; +- (NSException *)validateName: (NSString *) name; +- (void)setName: (NSString*)name; +- (void)setExternalName: (NSString*)name; +- (void)setExternalQuery: (NSString*)query; +- (void)setRestrictingQualifier: (EOQualifier *)qualifier; +- (void)setReadOnly: (BOOL)flag; +- (void)setCachesObjects: (BOOL)yn; + +- (void)addAttribute: (EOAttribute *)attribute; +- (void)removeAttribute: (EOAttribute *)attribute; + +- (void)addRelationship: (EORelationship *)relationship; +- (void)removeRelationship: (EORelationship *)relationship; + +- (void)addFetchSpecification: (EOFetchSpecification *)fetchSpec + named: (NSString *)name; +- (void)removeFetchSpecificationNamed: (NSString *)name; + +- (void)setClassName: (NSString*)name; +- (void)setUserInfo: (NSDictionary*)dictionary; +- (void) _setInternalInfo: (NSDictionary*)dictionary; +- (void) setDocComment:(NSString *)docComment; + +- (void)addSubEntity: (EOEntity *)child; +- (void)removeSubEntity: (EOEntity *)child; + +- (void)setIsAbstractEntity: (BOOL)f; +- (void)setMaxNumberOfInstancesToBatchFetch: (unsigned int)size; + +@end + + +@interface EOEntity (EOModelReferentialIntegrity) + +- (BOOL)referencesProperty:property; +- (NSArray *)externalModelsReferenced; + +@end + +@interface EOEntity (EOModelBeautifier) + +- (void)beautifyName; + +@end + +extern NSString *EOFetchAllProcedureOperation; +extern NSString *EOFetchWithPrimaryKeyProcedureOperation; +extern NSString *EOInsertProcedureOperation; +extern NSString *EODeleteProcedureOperation; +extern NSString *EONextPrimaryKeyProcedureOperation; + +@interface EOEntity (MethodSet11) +- (NSException *)validateObjectForDelete: (id)object; +- (id) classPropertyAttributeNames; +- (id) classPropertyToManyRelationshipNames; +- (id) classPropertyToOneRelationshipNames; +- (id) qualifierForDBSnapshot: (id)param0; +- (EOAttribute*) attributeForPath: (NSString*)path; +- (EORelationship*) relationshipForPath: (NSString*)path; +- (void) _addAttributesToFetchForRelationshipPath: (NSString*)path + atts: (NSMutableDictionary*)atts; +- (id) dbSnapshotKeys; +- (NSArray*) flattenedAttributes; +@end + +@interface EOEntity (EOStoredProcedures) + +- (EOStoredProcedure *)storedProcedureForOperation: (NSString *)operation; +- (void)setStoredProcedure: (EOStoredProcedure *)storedProcedure + forOperation: (NSString *)operation; + +@end + +@interface EOEntity (EOPrimaryKeyGeneration) + +- (NSString *)primaryKeyRootName; + +@end + +@interface EOEntity (EOEntityClassDescription) + +- (EOClassDescription *)classDescriptionForInstances; + +@end + +@interface EOEntity (EOEntityHidden) +- (NSDictionary*)attributesByName; +- (NSDictionary*)relationshipsByName; +- (NSArray*) _allFetchSpecifications; +- (NSDictionary*) _fetchSpecificationDictionary; +- (void) _loadEntity; +- (id) parentRelationship; +- (int) _numberOfRelationships; +- (BOOL) _hasReadOnlyAttributes; +- (NSArray*) writableDBSnapshotKeys; +- (NSArray*) rootAttributesUsedForLocking; +- (BOOL) isSubEntityOf:(id)param0; +- (id) initObject: (id)param0 + editingContext: (id)param1 + globalID: (id)param2; +- (id) allocBiggestObjectWithZone:(NSZone*)zone; +- (Class) _biggestClass; +- (NSArray*) relationshipsPlist; +- (id) rootParent; +- (void) _setParent: (id)param0; +- (NSArray*) _hiddenRelationships; +- (NSArray*) _propertyNames; +- (id) _flattenAttribute: (id)param0 + relationshipPath: (id)param1 + currentAttributes: (id)param2; +- (NSString*) snapshotKeyForAttributeName: (NSString*)attributeName; +- (id) _flattenedAttNameToSnapshotKeyMapping; +- (EOMKKDSubsetMapping*) _snapshotToAdaptorRowSubsetMapping; +- (EOMutableKnownKeyDictionary*) _dictionaryForPrimaryKey; +- (EOMutableKnownKeyDictionary*) _dictionaryForProperties; +- (NSArray*) _relationshipsToFaultForRow: (NSDictionary*)row; +- (NSArray*) _classPropertyAttributes; +- (NSArray*) _attributesToSave; +- (NSArray*) _attributesToFetch; +- (EOMKKDInitializer*) _adaptorDictionaryInitializer; +- (EOMKKDInitializer*) _snapshotDictionaryInitializer; +- (EOMKKDInitializer*) _primaryKeyDictionaryInitializer; +- (EOMKKDInitializer*) _propertyDictionaryInitializer; +- (void) _setModel: (EOModel*)model; +- (void) _setIsEdited; +- (NSArray*) _classPropertyAttributes; +@end + +@interface EOEntityClassDescription:EOClassDescription +{ + EOEntity *_entity; + unsigned int extraRefCount; +} + +/** returns an autoreleased entity class description for entity entity **/ ++ (EOEntityClassDescription*)entityClassDescriptionWithEntity: (EOEntity *)entity; + +/** initialize with entity **/ +- initWithEntity: (EOEntity *)entity; + +/** returns entity **/ +- (EOEntity *)entity; + +@end + +@interface NSString (EODatabaseNameConversion) + ++ (NSString *)nameForExternalName: (NSString *)externalName + separatorString: (NSString *)separatorString + initialCaps: (BOOL)initialCaps; ++ (NSString *)externalNameForInternalName: (NSString *)internalName + separatorString: (NSString *)separatorString + useAllCaps: (BOOL)allCaps; + +@end + +#endif /* __EOEntity_h__ */ diff --git a/EOAccess/EOEntity.m b/EOAccess/EOEntity.m new file mode 100644 index 0000000..a80cda6 --- /dev/null +++ b/EOAccess/EOEntity.m @@ -0,0 +1,4367 @@ +/** + EOEntity.m EOEntity Class + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + Author: Manuel Guesdon + Date: October 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import + +#import + +#import +#import +#import + +#import +#import +#import +#import +#import +#import +#import +#import + +#import +#import +#import +#import +#import +#import +#import +#import +#import + + +NSString *EOFetchAllProcedureOperation = @"EOFetchAllProcedureOperation"; +NSString *EOFetchWithPrimaryKeyProcedureOperation = @"EOFetchWithPrimaryKeyProcedureOperation"; +NSString *EOInsertProcedureOperation = @"EOInsertProcedureOperation"; +NSString *EODeleteProcedureOperation = @"EODeleteProcedureOperation"; +NSString *EONextPrimaryKeyProcedureOperation = @"EONextPrimaryKeyProcedureOperation"; + + +@implementation EOEntity + ++ (EOEntity *)entity +{ + return [[[self alloc] init] autorelease]; +} + ++ (EOEntity *)entityWithPropertyList: (NSDictionary *)propertyList + owner: (id)owner +{ + return [[[self alloc] initWithPropertyList: propertyList + owner: owner] autorelease]; +} + +- (id)initWithPropertyList: (NSDictionary *)propertyList + owner: (id)owner +{ + [EOObserverCenter suppressObserverNotification]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"propertyList=%@", propertyList); + + NS_DURING + { + if ((self = [self init])) + { + NSArray *array = nil; + NSString *tmpString = nil; + id tmpObject = nil; + + [self setCreateMutableObjects: YES]; + + ASSIGN(_name, [propertyList objectForKey: @"name"]); + + [self setExternalName: [propertyList objectForKey: @"externalName"]]; + [self setExternalQuery: [propertyList objectForKey: @"externalQuery"]]; + + tmpString = [propertyList objectForKey: @"restrictingQualifier"]; + + EOFLOGObjectLevelArgs(@"EOEntity",@"tmpString=%@",tmpString); + + if (tmpString) + { + EOQualifier *restrictingQualifier = + [EOQualifier qualifierWithQualifierFormat: @"%@", tmpString]; + + [self setRestrictingQualifier: restrictingQualifier]; + } + + tmpString = [propertyList objectForKey: @"mappingQualifier"]; + + if (tmpString) + { + NSEmitTODO(); //TODO + } + + [self setReadOnly: [[propertyList objectForKey: @"isReadOnly"] + boolValue]]; + [self setCachesObjects: [[propertyList objectForKey: + @"cachesObjects"] + boolValue]]; + tmpObject = [propertyList objectForKey: @"userInfo"]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"tmpObject=%@", tmpObject); + /*NSAssert2((!tmpString || [tmpString isKindOfClass:[NSString class]]), + @"tmpString is not a NSString but a %@. tmpString:\n%@", + [tmpString class], + tmpString); + */ + + if (tmpObject) + //[self setUserInfo:[tmpString propertyList]]; + [self setUserInfo: tmpObject]; + else + { + tmpObject = [propertyList objectForKey: @"userDictionary"]; + /*NSAssert2((!tmpString || [tmpString isKindOfClass:[NSString class]]), + @"tmpString is not a NSString but a %@ tmpString:\n%@", + [tmpString class], + tmpString);*/ + //[self setUserInfo:[tmpString propertyList]]; + [self setUserInfo: tmpObject]; + } + + tmpObject = [propertyList objectForKey: @"internalInfo"]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"tmpObject=%@ [%@]", + tmpObject, [tmpObject class]); + + [self _setInternalInfo: tmpObject]; + [self setDocComment:[propertyList objectForKey:@"docComment"]]; + [self setClassName: [propertyList objectForKey: @"className"]]; + [self setIsAbstractEntity: + [[propertyList objectForKey: @"isAbstractEntity"] boolValue]]; + + tmpString = [propertyList objectForKey: @"isFetchable"]; + + if (tmpString) + { + NSEmitTODO(); //TODO + } + + array = [propertyList objectForKey: @"attributes"]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"Attributes: %@", array); + + if ([array count] > 0) + { + ASSIGN(_attributes, array); + _flags.attributesIsLazy = YES; + } + + array = [propertyList objectForKey: @"attributesUsedForLocking"]; + EOFLOGObjectLevelArgs(@"EOEntity", @"attributesUsedForLocking: %@", + array); + if ([array count] > 0) + { + ASSIGN(_attributesUsedForLocking, array); + _flags.attributesUsedForLockingIsLazy = YES; + } + + array = [[propertyList objectForKey: @"primaryKeyAttributes"] + sortedArrayUsingSelector: @selector(compare:)]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"primaryKeyAttributes: %@", + array); + + if ([array count] > 0) + { + ASSIGN(_primaryKeyAttributes, array); + _flags.primaryKeyAttributesIsLazy = YES; + } + + //Assign them to _classProperties, not _classPropertyNames, this will be build after + array = [propertyList objectForKey: @"classProperties"]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"classProperties: %@", array); + + if ([array count] > 0) + { + ASSIGN(_classProperties, array); + _flags.classPropertiesIsLazy = YES; + } + + array = [propertyList objectForKey: @"relationships"]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"relationships: %@", array); + + if ([array count] > 0) + { + ASSIGN(_relationships, array); + _flags.relationshipsIsLazy = YES; + } + + array = [propertyList objectForKey: @"storedProcedureNames"]; + + EOFLOGObjectLevelArgs(@"EOEntity",@"relationships: %@",array); + if ([array count] > 0) + { + NSEmitTODO(); //TODO + } + + tmpString = [propertyList objectForKey: + @"maxNumberOfInstancesToBatchFetch"]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"maxNumberOfInstancesToBatchFetch=%@ [%@]", + tmpString, [tmpString class]); + + if (tmpString) + [self setMaxNumberOfInstancesToBatchFetch: [tmpString intValue]]; + + tmpString=[propertyList objectForKey:@"batchFaultingMaxSize"]; + if (tmpString) + { + NSEmitTODO(); //TODO + //[self setBatchFaultingMaxSize: [tmpString intValue]]; + } + + tmpObject = [propertyList objectForKey: + @"fetchSpecificationDictionary"]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"fetchSpecificationDictionary=%@ [%@]", + tmpObject, [tmpObject class]); + + if (tmpObject) + { + ASSIGN(_fetchSpecificationDictionary, tmpObject); + } + else + { + _fetchSpecificationDictionary = [NSDictionary new]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"Entity %@ - _fetchSpecificationDictionary %p [RC=%d]:%@", + [self name], + _fetchSpecificationDictionary, + [_fetchSpecificationDictionary retainCount], + _fetchSpecificationDictionary); + } + + // load entity's FetchSpecifications + { + NSDictionary *plist; + NSString *fileName; + + fileName = [NSString stringWithFormat: @"%@.fspec", _name]; + plist = [[NSString stringWithContentsOfFile: + [[(EOModel *)owner path] + stringByAppendingPathComponent: fileName]] + propertyList]; + + if (plist) + { + EOKeyValueUnarchiver *unarchiver; + NSDictionary *variables; + NSEnumerator *variablesEnum; + id fetchSpecName; + + unarchiver = [[[EOKeyValueUnarchiver alloc] + initWithDictionary: + [NSDictionary dictionaryWithObject: plist + forKey: @"fspecs"]] + autorelease]; + + variables = [unarchiver decodeObjectForKey: @"fspecs"]; + //NSLog(@"fspecs variables:%@",variables); + + [unarchiver finishInitializationOfObjects]; + [unarchiver awakeObjects]; + + variablesEnum = [variables keyEnumerator]; + while ((fetchSpecName = [variablesEnum nextObject])) + { + id fetchSpec = [variables objectForKey: fetchSpecName]; + + //NSLog(@"fetchSpecName:%@ fetchSpec:%@", fetchSpecName, fetchSpec); + + [self addFetchSpecification: fetchSpec + named: fetchSpecName]; + } + } + } + + [self setCreateMutableObjects: NO]; //?? TC say no, mirko yes + } + } + NS_HANDLER + { + [EOObserverCenter enableObserverNotification]; + + NSLog(@"exception in EOEntity initWithPropertyList:owner:"); + NSLog(@"exception=%@", localException); + +/* localException=ExceptionByAddingUserInfoObjectFrameInfo(localException, + @"In EOEntity initWithPropertyList:owner:");*/ + + NSLog(@"exception=%@", localException); + [localException raise]; + } + NS_ENDHANDLER; + + [EOObserverCenter enableObserverNotification]; + + return self; +} + +- (void)awakeWithPropertyList: (NSDictionary *)propertyList +{ + //do nothing? +} + +- (void)encodeIntoPropertyList: (NSMutableDictionary *)propertyList +{ + int i, count; + + if (_name) + [propertyList setObject: _name + forKey: @"name"]; + if (_className) + [propertyList setObject: _className + forKey: @"className"]; + if (_externalName) + [propertyList setObject: _externalName + forKey: @"externalName"]; + if (_externalQuery) + [propertyList setObject: _externalQuery + forKey: @"externalQuery"]; + if (_userInfo) + [propertyList setObject: _userInfo + forKey: @"userInfo"]; + if (_docComment) + [propertyList setObject: _docComment + forKey: @"docComment"]; + if (_batchCount) + [propertyList setObject: [NSNumber numberWithInt: _batchCount] + forKey: @"maxNumberOfInstancesToBatchFetch"]; + + if (_flags.cachesObjects) + [propertyList setObject: [NSNumber numberWithBool: _flags.cachesObjects] + forKey: @"cachesObjects"]; + + if ((count = [_attributes count])) + { + if (_flags.attributesIsLazy) + [propertyList setObject: _attributes + forKey: @"attributes"]; + else + { + NSMutableArray *attributesPList = [NSMutableArray array]; + + for (i = 0; i < count; i++) + { + NSMutableDictionary *attributePList = [NSMutableDictionary + dictionary]; + + [[_attributes objectAtIndex: i] + encodeIntoPropertyList: attributePList]; + [attributesPList addObject: attributePList]; + } + + [propertyList setObject: attributesPList + forKey: @"attributes"]; + } + } + + if ((count = [_attributesUsedForLocking count])) + { + if (_flags.attributesUsedForLockingIsLazy) + [propertyList setObject: _attributesUsedForLocking + forKey: @"attributesUsedForLocking"]; + else + { + NSMutableArray *attributesUsedForLockingPList = [NSMutableArray + array]; + + for (i = 0; i < count; i++) + { + NSString *attributePList + = [(EOAttribute *)[_attributesUsedForLocking objectAtIndex: i] + name]; + + [attributesUsedForLockingPList addObject: attributePList]; + } + + [propertyList setObject: attributesUsedForLockingPList + forKey: @"attributesUsedForLocking"]; + } + } + + if ((count = [_classProperties count])) + { + if (_flags.classPropertiesIsLazy) + [propertyList setObject: _classProperties + forKey: @"classProperties"]; + else + { + NSMutableArray *classPropertiesPList = [NSMutableArray array]; + + for (i = 0; i < count; i++) + { + NSString *classPropertyPList + = [(EOAttribute *)[_classProperties objectAtIndex: i] + name]; + [classPropertiesPList addObject: classPropertyPList]; + } + + [propertyList setObject: classPropertiesPList + forKey: @"classProperties"]; + } + } + + if ((count = [_primaryKeyAttributes count])) + { + if (_flags.primaryKeyAttributesIsLazy) + [propertyList setObject: _primaryKeyAttributes + forKey: @"primaryKeyAttributes"]; + else + { + NSMutableArray *primaryKeyAttributesPList = [NSMutableArray array]; + + for (i = 0; i < count; i++) + { + NSString *attributePList= [(EOAttribute *)[_primaryKeyAttributes + objectAtIndex: i] + name]; + + [primaryKeyAttributesPList addObject: attributePList]; + } + + [propertyList setObject: primaryKeyAttributesPList + forKey: @"primaryKeyAttributes"]; + } + } + + { + NSArray *relsPlist = [self relationshipsPlist]; + + if (relsPlist) + { + [propertyList setObject: relsPlist + forKey: @"relationships"]; + } + } +} + +- (id) init +{ + //OK + if ((self = [super init])) + { + } + + return self; +} + +- (void)dealloc +{ + DESTROY(_name); + DESTROY(_className); + DESTROY(_externalName); + DESTROY(_externalQuery); + DESTROY(_userInfo); + DESTROY(_docComment); + DESTROY(_primaryKeyAttributeNames); + DESTROY(_classPropertyNames); + DESTROY(_classDescription); + DESTROY(_adaptorDictionaryInitializer); + DESTROY(_snapshotDictionaryInitializer); + DESTROY(_primaryKeyDictionaryInitializer); + DESTROY(_propertyDictionaryInitializer); + DESTROY(_snapshotToAdaptorRowSubsetMapping); + DESTROY(_classForInstances); + + [super dealloc]; +} + +- (void)gcDecrementRefCountOfContainedObjects +{ + int where = 0; + NSProcessInfo *_processInfo = [NSProcessInfo processInfo]; + NSMutableSet *_debugSet = [_processInfo debugSet]; + + [_debugSet addObject: @"gsdb"]; + + EOFLOGObjectFnStart(); + EOFLOGObjectFnStart(); + + NS_DURING + { + where = 1; + [_model gcDecrementRefCount]; + + where = 2; + EOFLOGObjectLevelArgs(@"EOEntity", @"attributes gcDecrementRefCount"); + if (!_flags.attributesIsLazy) + [(id)_attributes gcDecrementRefCount]; + + where = 3; + EOFLOGObjectLevelArgs(@"EOEntity", + @"propertiesToFault gcDecrementRefCount"); + [(id)_attributesByName gcDecrementRefCount]; + + where = 4; + EOFLOGObjectLevelArgs(@"EOEntity", + @"attributesToFetch gcDecrementRefCount class=%@", + [_attributesToFetch class]); + NSAssert3(!_attributesToFetch + || [_attributesToFetch isKindOfClass: [NSArray class]], + @"entity %@ attributesToFetch is not an NSArray but a %@\n%@", + [self name], + [_attributesToFetch class], + _attributesToFetch); + + [(id)_attributesToFetch gcDecrementRefCount]; + + NSAssert3(!_attributesToFetch + || [_attributesToFetch isKindOfClass: [NSArray class]], + @"entity %@ attributesToFetch is not an NSArray but a %@\n%@", + [self name], + [_attributesToFetch class], + _attributesToFetch); + + where = 5; + EOFLOGObjectLevelArgs(@"EOEntity", + @"attributesToSave gcDecrementRefCount (class=%@)", + [_attributesToSave class]); + [(id)_attributesToSave gcDecrementRefCount]; + + where = 6; + EOFLOGObjectLevelArgs(@"EOEntity", + @"propertiesToFault gcDecrementRefCount"); + [(id)_propertiesToFault gcDecrementRefCount]; + + where = 7; + EOFLOGObjectLevelArgs(@"EOEntity", + @"rrelationships gcDecrementRefCount"); + if (!_flags.relationshipsIsLazy) + [(id)_relationships gcDecrementRefCount]; + + where = 8; + EOFLOGObjectLevelArgs(@"EOEntity", + @"relationshipsByName gcDecrementRefCount"); + [(id)_relationshipsByName gcDecrementRefCount]; + + where = 9; + EOFLOGObjectLevelArgs(@"EOEntity", + @"primaryKeyAttributes gcDecrementRefCount"); + if (!_flags.primaryKeyAttributesIsLazy) + [(id)_primaryKeyAttributes gcDecrementRefCount]; + + where = 10; + EOFLOGObjectLevelArgs(@"EOEntity", + @"classProperties gcDecrementRefCount"); + if (!_flags.classPropertiesIsLazy) + [(id)_classProperties gcDecrementRefCount]; + + where = 11; + EOFLOGObjectLevelArgs(@"EOEntity", + @"attributesUsedForLocking (%@) gcDecrementRefCount", + [_attributesUsedForLocking class]); + if (!_flags.attributesUsedForLockingIsLazy) + [(id)_attributesUsedForLocking gcDecrementRefCount]; + + where = 12; + EOFLOGObjectLevelArgs(@"EOEntity", @"subEntities gcDecrementRefCount"); + [(id)_subEntities gcDecrementRefCount]; + + where = 13; + EOFLOGObjectLevelArgs(@"EOEntity", @"dbSnapshotKeys gcDecrementRefCount"); + [(id)_dbSnapshotKeys gcDecrementRefCount]; + + where = 14; + EOFLOGObjectLevelArgs(@"EOEntity", @"_parent gcDecrementRefCount"); + [_parent gcDecrementRefCount]; + } + NS_HANDLER + { + NSLog(@"====>WHERE=%d %@ (%@)", where, localException, + [localException reason]); + NSDebugMLog(@"attributesToFetch gcDecrementRefCount class=%@", + [_attributesToFetch class]); + + [localException raise]; + } + NS_ENDHANDLER; + + EOFLOGObjectFnStop(); + + [_debugSet removeObject: @"gsdb"]; +} + +- (BOOL)gcIncrementRefCountOfContainedObjects +{ + int where = 0; + NSProcessInfo *_processInfo = [NSProcessInfo processInfo]; + NSMutableSet *_debugSet = [_processInfo debugSet]; + + [_debugSet addObject: @"gsdb"]; + + EOFLOGObjectFnStart(); + + if (![super gcIncrementRefCountOfContainedObjects]) + { + EOFLOGObjectFnStop(); + [_debugSet removeObject: @"gsdb"]; + + return NO; + } + NS_DURING + { + where = 1; + EOFLOGObjectLevelArgs(@"EOEntity", @"model gcIncrementRefCount"); + [_model gcIncrementRefCount]; + + where = 2; + EOFLOGObjectLevelArgs(@"EOEntity", @"attributes gcIncrementRefCount"); + if (!_flags.attributesIsLazy) + [(id)_attributes gcIncrementRefCount]; + + where = 3; + EOFLOGObjectLevelArgs(@"EOEntity", + @"attributesByName gcIncrementRefCount"); + [(id)_attributesByName gcIncrementRefCount]; + + where = 4; + EOFLOGObjectLevelArgs(@"EOEntity", + @"attributesToFetch gcIncrementRefCount"); + NSAssert3(!_attributesToFetch + || [_attributesToFetch isKindOfClass: [NSArray class]], + @"entity %@ attributesToFetch is not an NSArray but a %@\n%@", + [self name], + [_attributesToFetch class], + _attributesToFetch); + + [(id)_attributesToFetch gcIncrementRefCount]; + + NSAssert3(!_attributesToFetch + || [_attributesToFetch isKindOfClass: [NSArray class]], + @"entity %@ attributesToFetch is not an NSArray but a %@\n%@", + [self name], + [_attributesToFetch class], + _attributesToFetch); + + where = 5; + EOFLOGObjectLevelArgs(@"EOEntity", + @"attributesToSave gcIncrementRefCount"); + [(id)_attributesToSave gcIncrementRefCount]; + + where = 6; + EOFLOGObjectLevelArgs(@"EOEntity", + @"propertiesToFault gcIncrementRefCount"); + [(id)_propertiesToFault gcIncrementRefCount]; + + where = 7; + EOFLOGObjectLevelArgs(@"EOEntity", @"relationships gcIncrementRefCount"); + if (!_flags.relationshipsIsLazy) + [(id)_relationships gcIncrementRefCount]; + + where = 8; + EOFLOGObjectLevelArgs(@"EOEntity", + @"relationshipsByName gcIncrementRefCount"); + [(id)_relationshipsByName gcIncrementRefCount]; + + where = 9; + EOFLOGObjectLevelArgs(@"EOEntity", + @"primaryKeyAttributes gcIncrementRefCount"); + if (!_flags.primaryKeyAttributesIsLazy) + [(id)_primaryKeyAttributes gcIncrementRefCount]; + + where = 10; + EOFLOGObjectLevelArgs(@"EOEntity", + @"classProperties gcIncrementRefCount"); + if (!_flags.classPropertiesIsLazy) + [(id)_classProperties gcIncrementRefCount]; + + where = 11; + EOFLOGObjectLevelArgs(@"EOEntity", + @"attributesUsedForLocking gcIncrementRefCount"); + if (!_flags.attributesUsedForLockingIsLazy) + [(id)_attributesUsedForLocking gcIncrementRefCount]; + + where = 12; + EOFLOGObjectLevelArgs(@"EOEntity", @"subEntities gcIncrementRefCount"); + [(id)_subEntities gcIncrementRefCount]; + + where = 13; + EOFLOGObjectLevelArgs(@"EOEntity", @"dbSnapshotKeys gcIncrementRefCount"); + [(id)_dbSnapshotKeys gcIncrementRefCount]; + + where = 14; + EOFLOGObjectLevelArgs(@"EOEntity", @"parent gcIncrementRefCount"); + [_parent gcIncrementRefCount]; + + where = 15; + [_model gcIncrementRefCountOfContainedObjects]; + + where = 16; + EOFLOGObjectLevelArgs(@"EOEntity", @"attributes gcIncrementRefCountOfContainedObjects"); + if (!_flags.attributesIsLazy) + [(id)_attributes gcIncrementRefCountOfContainedObjects]; + + where = 17; + EOFLOGObjectLevelArgs(@"EOEntity", @"attributesByName gcIncrementRefCountOfContainedObjects"); + [(id)_attributesByName gcIncrementRefCountOfContainedObjects]; + + where = 18; + EOFLOGObjectLevelArgs(@"EOEntity", @"attributesToFetch gcIncrementRefCountOfContainedObjects"); + [(id)_attributesToFetch gcIncrementRefCountOfContainedObjects]; + + where = 19; + EOFLOGObjectLevelArgs(@"EOEntity", @"attributesToSave gcIncrementRefCountOfContainedObjects (class=%@)", + [_attributesToSave class]); + [(id)_attributesToSave gcIncrementRefCountOfContainedObjects]; + + where = 20; + EOFLOGObjectLevelArgs(@"EOEntity", @"propertiesToFault gcIncrementRefCountOfContainedObjects"); + [(id)_propertiesToFault gcIncrementRefCountOfContainedObjects]; + + where = 21; + EOFLOGObjectLevelArgs(@"EOEntity", @"rrelationships gcIncrementRefCountOfContainedObjects"); + if (!_flags.relationshipsIsLazy) + [(id)_relationships gcIncrementRefCountOfContainedObjects]; + + where = 22; + EOFLOGObjectLevelArgs(@"EOEntity", @"relationshipsByName gcIncrementRefCountOfContainedObjects"); + [(id)_relationshipsByName gcIncrementRefCountOfContainedObjects]; + + where = 23; + EOFLOGObjectLevelArgs(@"EOEntity", @"primaryKeyAttributes gcIncrementRefCountOfContainedObjects"); + if (!_flags.primaryKeyAttributesIsLazy) + [(id)_primaryKeyAttributes gcIncrementRefCountOfContainedObjects]; + + where = 24; + EOFLOGObjectLevelArgs(@"EOEntity", @"classProperties gcIncrementRefCountOfContainedObjects"); + if (!_flags.classPropertiesIsLazy) + [(id)_classProperties gcIncrementRefCountOfContainedObjects]; + + where = 25; + EOFLOGObjectLevelArgs(@"EOEntity", @"attributesUsedForLocking (%@) gcIncrementRefCountOfContainedObjects", + [_attributesUsedForLocking class]); + if (!_flags.attributesUsedForLockingIsLazy) + [(id)_attributesUsedForLocking gcIncrementRefCountOfContainedObjects]; + + where = 26; + EOFLOGObjectLevelArgs(@"EOEntity", @"subEntities gcIncrementRefCountOfContainedObjects"); + [(id)_subEntities gcIncrementRefCountOfContainedObjects]; + + where = 27; + EOFLOGObjectLevelArgs(@"EOEntity", @"dbSnapshotKeys gcIncrementRefCountOfContainedObjects"); + [(id)_dbSnapshotKeys gcIncrementRefCountOfContainedObjects]; + + where = 28; + EOFLOGObjectLevelArgs(@"EOEntity", @"_parent gcIncrementRefCountOfContainedObjects"); + [_parent gcIncrementRefCountOfContainedObjects]; + + where = 29; + } + NS_HANDLER + { + NSLog(@"====>WHERE=%d %@ (%@)", where, localException, + [localException reason]); + NSDebugMLog(@"attributes gcIncrementRefCountOfContainedObjects=%@", + [_attributes class]); + NSDebugMLog(@"_attributes classes %@", + [_attributes resultsOfPerformingSelector: @selector(class)]); + + [localException raise]; + } + NS_ENDHANDLER; + + EOFLOGObjectFnStop(); + + [_debugSet removeObject: @"gsdb"]; + + return YES; +} + +- (unsigned)hash +{ + return [_name hash]; +} + +- (NSString*)description +{ + NSString *dscr = nil; + + dscr = [NSString stringWithFormat: @"<%s %p - name=%@ className=%@ externalName=%@ externalQuery=%@", + object_get_class_name(self), + (void*)self, + _name, + _className, + _externalName, + _externalQuery]; + + dscr = [dscr stringByAppendingFormat:@" userInfo=%@", + _userInfo]; + dscr = [dscr stringByAppendingFormat:@" primaryKeyAttributeNames=%@ classPropertyNames=%@>", + [self primaryKeyAttributeNames], + [self classPropertyNames]]; + + NSAssert4(!_attributesToFetch + || [_attributesToFetch isKindOfClass:[NSArray class]], + @"entity %@ attributesToFetch %p is not an NSArray but a %@\n%@", + [self name], + _attributesToFetch, + [_attributesToFetch class], + _attributesToFetch); + + return dscr; +} + +- (EOQualifier *)restrictingQualifier +{ + return _restrictingQualifier; +} + +- (NSString *)name +{ + return _name; +} + +- (EOModel *)model +{ + return _model; +} + +- (NSDictionary *)userInfo +{ + return _userInfo; +} + +- (NSString *)docComment +{ + return _docComment; +} + +- (BOOL)isReadOnly +{ + return _flags.isReadOnly; +} + +- (NSString *)externalQuery +{ + return _externalQuery; +} + +- (NSString *)externalName +{ + EOFLOGObjectLevelArgs(@"EOEntity", @"entity %p (%@): external name=%@", + self, [self name], _externalName); + + return _externalName; +} + +- (NSString *)className +{ + return _className; +} + +- (NSArray *)attributesUsedForLocking +{ + //OK + if (_flags.attributesUsedForLockingIsLazy) + { + int count = [_attributesUsedForLocking count]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"Lazy _attributesUsedForLocking=%@", + _attributesUsedForLocking); + + if (count > 0) + { + int i = 0; + NSArray *attributesUsedForLocking = _attributesUsedForLocking; + + _attributesUsedForLocking = [GCMutableArray new]; + _flags.attributesUsedForLockingIsLazy = NO; + + for (i = 0; i < count; i++) + { + NSString *attributeName = [attributesUsedForLocking + objectAtIndex: i]; + EOAttribute *attribute = [self attributeNamed: attributeName]; + + NSAssert1(attribute, + @"No attribute named %@ to use for locking", + attribute); + + if ([self isValidAttributeUsedForLocking: attribute]) + [_attributesUsedForLocking addObject: attribute]; + else + { + NSEmitTODO(); //TODO + [self notImplemented: _cmd]; //TODO + } + } + + EOFLOGObjectLevelArgs(@"EOEntity", @"_attributesUsedForLocking class=%@", + [_attributesUsedForLocking class]); + + DESTROY(attributesUsedForLocking); + + [self _setIsEdited]; //To Clean Buffers + } + else + _flags.attributesUsedForLockingIsLazy = NO; + } + + return _attributesUsedForLocking; +} + +- (NSArray *)classPropertyNames +{ + //OK + EOFLOGObjectFnStart(); + + if (!_classPropertyNames) + { + NSArray *classProperties = [self classProperties]; + + NSAssert2(!classProperties + || [classProperties isKindOfClass: [NSArray class]], + @"classProperties is not an NSArray but a %@\n%@", + [classProperties class], + classProperties); + + ASSIGN(_classPropertyNames, + [classProperties resultsOfPerformingSelector: @selector(name)]); + } + + NSAssert4(!_attributesToFetch + || [_attributesToFetch isKindOfClass: [NSArray class]], + @"entity %@ attributesToFetch %p is not an NSArray but a %@\n%@", + [self name], + _attributesToFetch, + [_attributesToFetch class], + _attributesToFetch); + + EOFLOGObjectFnStop(); + + return _classPropertyNames; +} + +- (NSArray *)classProperties +{ + //OK + EOFLOGObjectFnStart(); + + if (_flags.classPropertiesIsLazy) + { + int count = [_classProperties count]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"Lazy _classProperties=%@", + _classProperties); + + if (count > 0) + { + NSArray *classPropertiesList = _classProperties; + int i; + + _classProperties = [GCMutableArray new]; + _flags.classPropertiesIsLazy = NO; + + for (i = 0; i < count; i++) + { + NSString *classPropertyName = [classPropertiesList + objectAtIndex: i]; + id classProperty = [self attributeNamed: classPropertyName]; + + if (!classProperty) + classProperty = [self relationshipNamed: classPropertyName]; + + NSAssert2(classProperty, + @"No attribute or relationship named %@ to use as classProperty in entity %@", + classPropertyName, + self); + + if ([self isValidClassProperty: classProperty]) + [_classProperties addObject: classProperty]; + else + { + //TODO + NSAssert2(NO, @"not valid class prop %@ in %@", + classProperty, [self name]); + } + } + + DESTROY(classPropertiesList); + + [_classProperties sortUsingSelector: @selector(eoCompareOnName:)]; //Very important to have always the same order. + [self _setIsEdited]; //To Clean Buffers + } + else + _flags.classPropertiesIsLazy = NO; + } + + EOFLOGObjectFnStop(); + + return _classProperties; +} + +- (NSArray *)primaryKeyAttributes +{ + //OK + if (_flags.primaryKeyAttributesIsLazy) + { + int count = [_primaryKeyAttributes count]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"Lazy _primaryKeyAttributes=%@", + _primaryKeyAttributes); + + if (count > 0) + { + int i = 0; + NSArray *primaryKeyAttributes = _primaryKeyAttributes; + + _primaryKeyAttributes = [GCMutableArray new]; + _flags.primaryKeyAttributesIsLazy = NO; + + for (i = 0; i < count; i++) + { + NSString *attributeName = [primaryKeyAttributes objectAtIndex: i]; + EOAttribute *attribute = [self attributeNamed: attributeName]; + + NSAssert3(attribute, + @"In entity %@: No attribute named %@ to use for locking (attributes: %@)", + [self name], + attributeName, + [_attributes resultsOfPerformingSelector: @selector(name)]); + + if ([self isValidPrimaryKeyAttribute: attribute]) + [_primaryKeyAttributes addObject: attribute]; + else + { + NSAssert2(NO, @"not valid pk attribute %@ in %@", + attribute, [self name]); + } + } + + DESTROY(primaryKeyAttributes); + + [primaryKeyAttributes sortUsingSelector: @selector(eoCompareOnName:)]; //Very important to have always the same order. + [self _setIsEdited]; //To Clean Buffers + } + else + _flags.primaryKeyAttributesIsLazy = NO; + } + + return _primaryKeyAttributes; +} + +- (NSArray *)primaryKeyAttributeNames +{ + //OK + if (!_primaryKeyAttributeNames) + { + NSArray *primaryKeyAttributes = [self primaryKeyAttributes]; + NSArray *primaryKeyAttributeNames = [primaryKeyAttributes + resultsOfPerformingSelector: + @selector(name)]; + + primaryKeyAttributeNames = [primaryKeyAttributeNames sortedArrayUsingSelector: @selector(compare:)]; //Not necessary: they are already sorted + ASSIGN(_primaryKeyAttributeNames, primaryKeyAttributeNames); + } + + return _primaryKeyAttributeNames; +} + +- (NSArray *)relationships +{ + //OK + if (_flags.relationshipsIsLazy) + { + int count = 0; + + EOFLOGObjectLevelArgs(@"EOEntity", @"START construct relationships on %p", + self); + + count = [_relationships count]; + EOFLOGObjectLevelArgs(@"EOEntity", @"Lazy _relationships=%@", + _relationships); + + if (count > 0) + { + int i = 0; + NSArray *relationshipPLists = _relationships; + NSDictionary *attributesByName = nil; + + DESTROY(_relationshipsByName); + + _relationships = [GCMutableArray new]; + _relationshipsByName = [GCMutableDictionary new]; + + if (!_flags.attributesIsLazy) + { + attributesByName = [self attributesByName]; + NSAssert2((!attributesByName + || [attributesByName isKindOfClass: + [NSDictionary class]]), + @"attributesByName is not a NSDictionary but a %@. attributesByName [%p]", + [attributesByName class], + attributesByName); + } + + _flags.relationshipsIsLazy = NO; + [EOObserverCenter suppressObserverNotification]; + + NS_DURING + { + NSArray *relNames = nil; + + for (i = 0; i < count; i++) + { + NSDictionary *attrPList = [relationshipPLists + objectAtIndex: i]; + EORelationship *relationship = nil; + NSString *relationshipName = nil; + + EOFLOGObjectLevelArgs(@"EOEntity", @"attrPList: %@", + attrPList); + + relationship = [EORelationship + relationshipWithPropertyList: attrPList + owner: self]; + + relationshipName = [relationship name]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"relationshipName: %@", + relationshipName); + + if ([attributesByName objectForKey: relationshipName]) + { + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: \"%@\" already used in the model as attribute", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + relationshipName]; + } + + if ([_relationshipsByName objectForKey: relationshipName]) + { + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: \"%@\" already used in the model", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + relationshipName]; + } + + EOFLOGObjectLevelArgs(@"EOEntity", @"Add rel %p", + relationship); + EOFLOGObjectLevelArgs(@"EOEntity", @"Add rel=%@", + relationship); + + [_relationships addObject: relationship]; + [_relationshipsByName setObject: relationship + forKey: relationshipName]; + } + + EOFLOGObjectLevelArgs(@"EOEntity", @"Rels added"); + + [self _setIsEdited];//To Clean Buffers + relNames = [_relationships + resultsOfPerformingSelector: @selector(name)]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"relNames=%@", relNames); + + count = [relNames count]; + EOFLOGObjectLevelArgs(@"EOEntity", @"self=%p rel count=%d", + self, count); + + NSAssert(count == [relationshipPLists count], + @"Error during attribute creations"); + { + int pass = 0; + + //We'll first awake non flattened relationships + for (pass = 0; pass < 2; pass++) + { + for (i = 0; i < count; i++) + { + NSString *relName = [relNames objectAtIndex: i]; + NSDictionary *relPList = [relationshipPLists + objectAtIndex: i]; + EORelationship *relationship = [self relationshipNamed: + relName]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"relName=%@", + relName); + + if ((pass == 0 + && ![relPList objectForKey: @"definition"]) + || (pass == 1 + && [relPList objectForKey: @"definition"])) + { + EOFLOGObjectLevelArgs(@"EOEntity", @"XXX REL: self=%p AWAKE relationship=%@", + self, relationship); + + [relationship awakeWithPropertyList: relPList]; + } + } + } + } + } + NS_HANDLER + { + EOFLOGObjectLevelArgs(@"EOEntity", @"localException=%@", + localException); + + DESTROY(relationshipPLists); + + [EOObserverCenter enableObserverNotification]; + [localException raise]; + } + NS_ENDHANDLER; + + DESTROY(relationshipPLists); + + [EOObserverCenter enableObserverNotification]; + } + else + _flags.relationshipsIsLazy = NO; + + EOFLOGObjectLevelArgs(@"EOEntity", @"STOP construct relationships on %p", + self); + } + + return _relationships; +} + +- (NSArray *)attributes +{ + //OK + if (_flags.attributesIsLazy) + { + int count = 0; + + EOFLOGObjectLevelArgs(@"EOEntity", @"START construct attributes on %p", + self); + + count = [_attributes count]; + EOFLOGObjectLevelArgs(@"EOEntity", @"Entity %@: Lazy _attributes=%@", + [self name], + _attributes); + + if (count > 0) + { + int i = 0; + NSArray *attributePLists = _attributes; + NSDictionary *relationshipsByName = nil; + + DESTROY(_attributesByName); + + _attributes = [GCMutableArray new]; + _attributesByName = [GCMutableDictionary new]; + + NSAssert2((!_attributesByName + || [_attributesByName isKindOfClass: + [NSDictionary class]]), + @"_attributesByName is not a NSDictionary but a %@. _attributesByName [%p]", + [_attributesByName class], + _attributesByName); + + if (!_flags.relationshipsIsLazy) + relationshipsByName = [self relationshipsByName]; + + _flags.attributesIsLazy = NO; + + [EOObserverCenter suppressObserverNotification]; + + NS_DURING + { + NSArray *attrNames = nil; + + for (i = 0; i < count; i++) + { + NSDictionary *attrPList = [attributePLists objectAtIndex: i]; + EOAttribute *attribute = [EOAttribute + attributeWithPropertyList: + attrPList + owner: self]; + NSString *attributeName = [attribute name]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"XXX 1 ATTRIBUTE: attribute=%@", + attribute); + + if ([_attributesByName objectForKey: attributeName]) + { + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: \"%@\" already used in the model as attribute", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + attributeName]; + } + + if ([relationshipsByName objectForKey: attributeName]) + { + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: \"%@\" already used in the model", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + attributeName]; + } + + EOFLOGObjectLevelArgs(@"EOEntity", @"Add attribute: %@", + attribute); + + [_attributes addObject: attribute]; + [_attributesByName setObject: attribute + forKey: attributeName]; + } + + EOFLOGObjectLevelArgs(@"EOEntity", @"_attributesByName class=%@", + [_attributesByName class]); + NSAssert2((!_attributesByName + || [_attributesByName isKindOfClass: + [NSDictionary class]]), + @"_attributesByName is not a NSDictionary but a %@. _attributesByName [%p]", + [_attributesByName class], + _attributesByName); + + EOFLOGObjectLevelArgs(@"EOEntity", @"_attributes [%p]=%@", + _attributes, _attributes); + EOFLOGObjectLevelArgs(@"EOEntity", @"_attributesByName class=%@", + [_attributesByName class]); + EOFLOGObjectLevelArgs(@"EOEntity", @"_attributesByName [%p]", + _attributesByName); + EOFLOGObjectLevelArgs(@"EOEntity", @"_attributesByName class=%@", + [_attributesByName class]); + //TODO[self _setIsEdited];//To Clean Buffers + EOFLOGObjectLevelArgs(@"EOEntity", @"_attributesByName [%p]", + _attributesByName); + EOFLOGObjectLevelArgs(@"EOEntity", @"_attributesByName class=%@", + [_attributesByName class]); + + NSAssert2((!_attributesByName + || [_attributesByName isKindOfClass: + [NSDictionary class]]), + @"_attributesByName is not a NSDictionary but a %@. _attributesByName [%p]", + [_attributesByName class], + _attributesByName); + + attrNames = [_attributes resultsOfPerformingSelector: + @selector(name)]; + NSAssert2((!_attributesByName + || [_attributesByName isKindOfClass: + [NSDictionary class]]), + @"_attributesByName is not a NSDictionary but a %@. _attributesByName [%p]", + [_attributesByName class], + _attributesByName); + + EOFLOGObjectLevelArgs(@"EOEntity", @"attrNames [%p]=%@", + attrNames, attrNames); + + count = [attrNames count]; + EOFLOGObjectLevelArgs(@"EOEntity", @"self=%p Attributes count=%d", + self, count); + NSAssert(count == [attributePLists count], + @"Error during attribute creations"); + EOFLOGObjectLevelArgs(@"EOEntity", @"attributePLists=%@", + attributePLists); + EOFLOGObjectLevelArgs(@"EOEntity", @"self=%p attributePLists count=%d", + self, [attributePLists count]); + + { + int pass = 0; + + //We'll first awake non derived/flattened attributes + for (pass = 0; pass < 2; pass++) + { + for (i = 0; i < count; i++) + { + NSString *attrName = [attrNames objectAtIndex: i]; + NSDictionary *attrPList = [attributePLists + objectAtIndex: i]; + EOAttribute *attribute = nil; + + EOFLOGObjectLevelArgs(@"EOEntity", @"XXX attrName=%@", + attrName); + + if ((pass == 0 && + ![attrPList objectForKey: @"definition"]) + || (pass == 1 + && [attrPList objectForKey: @"definition"])) + { + attribute = [self attributeNamed: attrName]; + EOFLOGObjectLevelArgs(@"EOEntity", @"XXX 2A ATTRIBUTE: self=%p AWAKE attribute=%@", + self, attribute); + + [attribute awakeWithPropertyList: attrPList]; + EOFLOGObjectLevelArgs(@"EOEntity", @"XXX 2B ATTRIBUTE: self=%p attribute=%@", + self, attribute); + } + } + } + } + NSAssert2((!_attributesByName + || [_attributesByName isKindOfClass: + [NSDictionary class]]), + @"_attributesByName is not a NSDictionary but a %@. _attributesByName [%p]", + [_attributesByName class], + _attributesByName); + } + NS_HANDLER + { + DESTROY(attributePLists); + [EOObserverCenter enableObserverNotification]; + [localException raise]; + } + NS_ENDHANDLER; + + DESTROY(attributePLists); + + [EOObserverCenter enableObserverNotification]; + [_attributes sortUsingSelector: @selector(eoCompareOnName:)];//Very important to have always the same order. + } + else + _flags.attributesIsLazy = NO; + + EOFLOGObjectLevelArgs(@"EOEntity", @"STOP construct attributes on %p", + self); + } + + return _attributes; +} + +- (BOOL)cachesObjects +{ + return _flags.cachesObjects; +} + +- (EOQualifier *)qualifierForPrimaryKey: (NSDictionary *)row +{ + //OK + EOQualifier *qualifier = nil; + NSArray *primaryKeyAttributeNames = [self primaryKeyAttributeNames]; + int count = [primaryKeyAttributeNames count]; + + if (count == 1) + { + //OK + NSString *key = [primaryKeyAttributeNames objectAtIndex: 0]; + id value = [row objectForKey: key]; + + qualifier = [EOKeyValueQualifier qualifierWithKey: key + operatorSelector: + EOQualifierOperatorEqual + value: value]; + } + else + { + //Seems OK + NSMutableArray *array = [NSMutableArray arrayWithCapacity: count]; + int i; + + for (i = 0; i < count; i++) + { + NSString *key = [primaryKeyAttributeNames objectAtIndex: i]; + id value = [row objectForKey: key]; + + [array addObject: [EOKeyValueQualifier qualifierWithKey: key + operatorSelector: + EOQualifierOperatorEqual + value: value]]; + } + + qualifier = [EOAndQualifier qualifierWithQualifierArray: array]; + } + + return qualifier; +} + +- (BOOL)isQualifierForPrimaryKey: (EOQualifier *)qualifier +{ + int count = [[self primaryKeyAttributeNames] count]; + + if (count == 1) + { + if ([qualifier isKindOfClass: [EOKeyValueQualifier class]] == YES) + return YES; + else + return NO; + } + else + { + } + + //TODO + NSEmitTODO(); //TODO + [self notImplemented:_cmd]; + + return NO; +} + +- (EOAttribute *)attributeNamed: (NSString *)attributeName +{ + //OK + EOAttribute *attribute = nil; + NSDictionary *attributesByName = nil; + + EOFLOGObjectFnStart(); + + attributesByName = [self attributesByName]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"attributesByName [%p] (%@)", + attributesByName, + [attributesByName class]); + NSAssert2((!attributesByName + || [attributesByName isKindOfClass: [NSDictionary class]]), + @"attributesByName is not a NSDictionary but a %@. attributesByName [%p]", + [attributesByName class], + attributesByName); + // EOFLOGObjectLevelArgs(@"EOEntity",@"attributesByName=%@",attributesByName); + + attribute = [attributesByName objectForKey: attributeName]; + + EOFLOGObjectFnStop(); + + return attribute; +} + +/** returns attribute named attributeName (no relationship) **/ +- (EOAttribute *)anyAttributeNamed: (NSString *)attributeName +{ + EOAttribute *attr; + NSEnumerator *attrEnum; + + attr = [self attributeNamed:attributeName]; + + //VERIFY + if (!attr) + { + attrEnum = [[self primaryKeyAttributes] objectEnumerator]; + + while ((attr = [attrEnum nextObject])) + { + if ([[attr name] isEqual: attributeName]) + return attr; + } + } + + return attr; +} + +- (EORelationship *)relationshipNamed: (NSString *)relationshipName +{ + //OK + return [[self relationshipsByName] objectForKey: relationshipName]; +} + +- (EORelationship *)anyRelationshipNamed: (NSString *)relationshipNamed +{ + EORelationship *rel; + NSEnumerator *relEnum = nil; + + rel = [self relationshipNamed: relationshipNamed]; + + //VERIFY + if (!rel) + { + EORelationship *tmpRel = nil; + + relEnum = [_hiddenRelationships objectEnumerator]; + + while (!rel && (tmpRel = [relEnum nextObject])) + { + if ([[tmpRel name] isEqual: relationshipNamed]) + rel = tmpRel; + } + } + + return rel; +} + +- (NSArray *)fetchSpecificationNames +{ + return _fetchSpecificationNames; +} + +- (EOFetchSpecification *)fetchSpecificationNamed: (NSString *)fetchSpecName +{ + return [_fetchSpecificationDictionary objectForKey: fetchSpecName]; +} + +- (NSArray *)attributesToFetch +{ + //OK + NSAssert3(!_attributesToFetch + | [_attributesToFetch isKindOfClass: [NSArray class]], + @"entity %@ attributesToFetch %p is not an NSArray but a %@", + [self name], + _attributesToFetch, + [_attributesToFetch class]); + + return [self _attributesToFetch]; +} + +- (NSDictionary *)primaryKeyForRow: (NSDictionary *)row +{ + NSMutableDictionary *dict = nil; + int i, count; + NSArray *primaryKeyAttributes = [self primaryKeyAttributes]; + + count = [primaryKeyAttributes count]; + dict = [NSMutableDictionary dictionaryWithCapacity: count]; + + for (i = 0; i < count; i++) + { + EOAttribute *attr = [primaryKeyAttributes objectAtIndex: i]; + id value = [row objectForKey: [attr name]]; + + if (!value) + value = [EONull null]; + + [dict setObject: value + forKey: [attr name]]; + } + + return dict; +} + +- (BOOL)isValidAttributeUsedForLocking: (EOAttribute *)anAttribute +{ + if (!([anAttribute isKindOfClass: [EOAttribute class]] + && [[self attributesByName] objectForKey: [anAttribute name]])) + return NO; + + if ([anAttribute isDerived]) + return NO; + + return YES; +} + +- (BOOL)isValidPrimaryKeyAttribute: (EOAttribute *)anAttribute +{ + if (!([anAttribute isKindOfClass: [EOAttribute class]] + && [[self attributesByName] objectForKey: [anAttribute name]])) + return NO; + + if ([anAttribute isDerived]) + return NO; + + return YES; +} + +- (BOOL)isPrimaryKeyValidInObject: (id)object +{ + NSArray *primaryKeyAttributeNames = nil; + NSString *key = nil; + id value = nil; + int i, count; + BOOL isValid = YES; + + primaryKeyAttributeNames = [self primaryKeyAttributeNames]; + count = [primaryKeyAttributeNames count]; + + for (i = 0; isValid && i < count; i++) + { + key = [primaryKeyAttributeNames objectAtIndex: i]; + + NS_DURING + { + value = [object valueForKey: key]; + if (value == nil || value == [EONull null]) + isValid = NO; + } + NS_HANDLER + { + isValid = NO; + } + NS_ENDHANDLER; + } + + return isValid; +} + +- (BOOL)isValidClassProperty:aProperty +{ + id thePropertyName; + + if (!([aProperty isKindOfClass: [EOAttribute class]] + || [aProperty isKindOfClass: [EORelationship class]])) + return NO; + + thePropertyName = [(EOAttribute *)aProperty name]; + + if ([[self attributesByName] objectForKey: thePropertyName] + || [[self relationshipsByName] objectForKey: thePropertyName]) + return YES; + + return NO; +} + +- (NSArray *)subEntities +{ + return _subEntities; +} + +- (EOEntity *)parentEntity +{ + return _parent; +} + +- (BOOL)isAbstractEntity +{ + return _flags.isAbstractEntity; +} + + +- (unsigned int)maxNumberOfInstancesToBatchFetch +{ + return _batchCount; +} + +- (BOOL)isPrototypeEntity +{ + [self notImplemented:_cmd]; + return NO; // TODO +} + +@end + + +@implementation EOEntity (EOEntityEditing) + +- (void)setUserInfo: (NSDictionary *)dictionary +{ + //OK + [self willChange]; + ASSIGN(_userInfo, dictionary); + [self _setIsEdited]; +} + +- (void)_setInternalInfo: (NSDictionary *)dictionary +{ + //OK + [self willChange]; + ASSIGN(_internalInfo, dictionary); + [self _setIsEdited]; +} + +- (void)setDocComment: (NSString *)docComment +{ + //OK + [self willChange]; + ASSIGN(_docComment, docComment); + [self _setIsEdited]; +} + +- (BOOL)setClassProperties: (NSArray *)properties +{ + int i, count = [properties count]; + + for (i = 0; i < count; i++) + if (![self isValidClassProperty: [properties objectAtIndex:i]]) + return NO; + + DESTROY(_classProperties); + if ([properties isKindOfClass:[GCArray class]] + || [properties isKindOfClass: [GCMutableArray class]]) + _classProperties = [[GCMutableArray alloc] initWithArray: properties]; + else + _classProperties = [[GCMutableArray alloc] initWithArray: properties]; //TODO + + [self _setIsEdited]; //To clean cache + + return YES; +} + +- (BOOL)setPrimaryKeyAttributes: (NSArray *)keys +{ + int i, count = [keys count]; + + for (i = 0; i < count; i++) + if (![self isValidPrimaryKeyAttribute: [keys objectAtIndex:i]]) + return NO; + + DESTROY(_primaryKeyAttributes); + + if ([keys isKindOfClass:[GCArray class]] + || [keys isKindOfClass: [GCMutableArray class]]) + _primaryKeyAttributes = [[GCMutableArray alloc] initWithArray: keys]; + else + _primaryKeyAttributes = [[GCMutableArray alloc] initWithArray: keys]; // TODO + + [self _setIsEdited];//To clean cache + + return YES; +} + +- (BOOL)setAttributesUsedForLocking: (NSArray *)attributes +{ + int i, count = [attributes count]; + + for (i = 0; i < count; i++) + if (![self isValidAttributeUsedForLocking: [attributes objectAtIndex: i]]) + return NO; + + DESTROY(_attributesUsedForLocking); + + if ([attributes isKindOfClass: [GCArray class]] // TODO + || [attributes isKindOfClass: [GCMutableArray class]]) + _attributesUsedForLocking = [[GCMutableArray alloc] + initWithArray: attributes]; + else + _attributesUsedForLocking = [[GCMutableArray alloc] + initWithArray: attributes]; + + [self _setIsEdited]; //To clean cache + + return YES; +} + +- (NSException *)validateName: (NSString *)name +{ + const char *p, *s = [name cString]; + int exc = 0; + NSArray *storedProcedures; + + if (!name || ![name length]) exc++; + if (!exc) + { + p = s; + while (*p) + { + if (!isalnum(*p) && + *p != '@' && *p != '#' && *p != '_' && *p != '$') + { + exc++; + break; + } + p++; + } + if (!exc && *s == '$') exc++; + + if ([self attributeNamed: name]) exc++; + else if ([self relationshipNamed: name]) exc++; + else if ((storedProcedures = [[self model] storedProcedures])) + { + NSEnumerator *stEnum = [storedProcedures objectEnumerator]; + EOStoredProcedure *st; + + while ((st = [stEnum nextObject])) + { + NSEnumerator *attrEnum; + EOAttribute *attr; + + attrEnum = [[st arguments] objectEnumerator]; + while ((attr = [attrEnum nextObject])) + { + if ([name isEqualToString: [attr name]]) + { + exc++; + break; + } + } + + if (exc) break; + } + } + } + + if (exc) + return [NSException exceptionWithName: NSInvalidArgumentException + reason: [NSString stringWithFormat:@"%@ -- %@ 0x%x: argument \"%@\" contains invalid chars", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + name] + userInfo: nil]; + else + return nil; +} + +- (void)setName: (NSString *)name +{ + if ([_model entityNamed: name]) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: \"%@\" already used in the model", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + name]; + + ASSIGN(_name, name); +} + +- (void)setExternalName: (NSString *)name +{ + //OK + EOFLOGObjectLevelArgs(@"EOEntity", @"entity %p (%@): external name=%@", + self, [self name], name); + + [self willChange]; + ASSIGN(_externalName,name); + [self _setIsEdited]; +} + +- (void)setExternalQuery: (NSString *)query +{ + //OK + [self willChange]; + ASSIGN(_externalQuery, query); + [self _setIsEdited]; +} + +- (void)setRestrictingQualifier: (EOQualifier *)qualifier +{ + ASSIGN(_restrictingQualifier, qualifier); +} + +- (void)setReadOnly: (BOOL)flag +{ + //OK + _flags.isReadOnly = flag; +} + +- (void)setCachesObjects: (BOOL)flag +{ + //OK + _flags.cachesObjects = flag; +} + +- (void)addAttribute: (EOAttribute *)attribute +{ + NSString *attributeName = [attribute name]; + + if ([[self attributesByName] objectForKey: attributeName]) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: \"%@\" already used in the model", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + attributeName]; + + if ([[self relationshipsByName] objectForKey: attributeName]) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: \"%@\" already used in the model as relationship", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + attributeName]; + + if ([self createsMutableObjects]) + [(GCMutableArray *)_attributes addObject: attribute]; + else + _attributes = [[[_attributes autorelease] + arrayByAddingObject: attribute] retain]; + + [self _setIsEdited]; //To clean caches + [attribute setParent: self]; +} + +- (void)removeAttribute: (EOAttribute *)attribute +{ + if (attribute) + { + [attribute setParent: nil]; + NSEmitTODO(); //TODO + + //TODO + if ([self createsMutableObjects]) + [(GCMutableArray *)_attributes removeObject: attribute]; + else + { + _attributes = [[_attributes autorelease] mutableCopy]; + [(GCMutableArray *)_attributes removeObject: attribute]; + _attributes = [[_attributes autorelease] copy]; + } + [self _setIsEdited];//To clean caches + } +} + +- (void)addRelationship: (EORelationship *)relationship +{ + NSString *relationshipName = [relationship name]; + + if ([[self attributesByName] objectForKey: relationshipName]) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: \"%@\" already used in the model as attribute", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + relationshipName]; + + if ([[self relationshipsByName] objectForKey: relationshipName]) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: \"%@\" already used in the model", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + relationshipName]; + + if ([self createsMutableObjects]) + [(GCMutableArray *)_relationships addObject: relationship]; + else + _relationships = [[[_relationships autorelease] + arrayByAddingObject: relationship] retain]; + + [relationship setEntity: self]; + [self _setIsEdited];//To clean caches +} + +- (void)removeRelationship: (EORelationship *)relationship +{ + NSEmitTODO(); //TODO + + //TODO + if (relationship) + { + [relationship setEntity:nil]; + + if ([self createsMutableObjects]) + [(GCMutableArray *)_relationships removeObject: relationship]; + else + { + _relationships = [[_relationships autorelease] mutableCopy]; + [(GCMutableArray *)_relationships removeObject: relationship]; + _relationships = [[_relationships autorelease] copy]; + } + [self _setIsEdited];//To clean caches + } +} + +- (void)addFetchSpecification: (EOFetchSpecification *)fetchSpec + named: (NSString *)name +{ + [_fetchSpecificationDictionary setObject: fetchSpec forKey: name]; + ASSIGN(_fetchSpecificationNames, [[_fetchSpecificationDictionary allKeys] + sortedArrayUsingSelector: + @selector(compare:)]); +} + +- (void)removeFetchSpecificationNamed: (NSString *)name +{ + [_fetchSpecificationDictionary removeObjectForKey:name]; + ASSIGN(_fetchSpecificationNames, [[_fetchSpecificationDictionary allKeys] + sortedArrayUsingSelector: + @selector(compare:)]); +} + +- (void)setClassName:(NSString *)name +{ + //OK + [self willChange]; + + if (!name) + { + NSLog(@"Entity %@ has no class name. Use EOGenericRecord", [self name]); + name = @"EOGenericRecord"; + } + ASSIGN(_className, name); + [self _setIsEdited]; +} + +- (void)addSubEntity: (EOEntity *)child +{ + [_subEntities addObject: child]; + [child setParentEntity: self]; +} + +- (void)removeSubEntity: (EOEntity *)child +{ + [child setParentEntity: nil]; + [_subEntities removeObject: child]; +} + +- (void)setIsAbstractEntity: (BOOL)f +{ + //OK + _flags.isAbstractEntity = f; +} + +- (void)setMaxNumberOfInstancesToBatchFetch: (unsigned int)size +{ + _batchCount = size; +} + +@end + + +@implementation EOEntity (EOModelReferentialIntegrity) + +- (BOOL)referencesProperty: property +{ + NSEnumerator *enumerator; + EORelationship *rel; + EOAttribute *attr; + + enumerator = [[self attributes] objectEnumerator]; + while ((attr = [enumerator nextObject])) + { + if ([attr isFlattened] && [[attr realAttribute] isEqual: property]) + return YES; + } + + enumerator = [[self relationships] objectEnumerator]; + while ((rel = [enumerator nextObject])) + { + if ([rel referencesProperty: property]) + return YES; + } + + return NO; +} + +- (NSArray *)externalModelsReferenced +{ + NSEmitTODO(); //TODO + return nil; // TODO +} + +@end + + +@implementation EOEntity (EOModelBeautifier) + +- (void)beautifyName +{ + //VERIFY + NSString *name = [self name]; + + [self setName: name]; + + [[self attributes] makeObjectsPerformSelector: @selector(beautifyName)]; + [[self relationships] makeObjectsPerformSelector: @selector(beautifyName)]; + [[self flattenedAttributes] makeObjectsPerformSelector: @selector(beautifyName)]; + +//Turbocat: +/* +// Make the entity name and all of its components conform +// to the Next naming style +// NAME -> name, FIRST_NAME -> firstName + + NSArray *listItems; + NSString *newString=[NSString string]; + int anz,i; + + EOFLOGObjectFnStartOrCond2(@"ModelingClasses",@"EOEntity"); + + // Makes the receiver's name conform to a standard convention. Names that conform to this style are all lower-case except for the initial letter of each embedded word other than the first, which is upper case. Thus, "NAME" becomes "name", and "FIRST_NAME" becomes "firstName". + + if ((_name) && ([_name length]>0)) { + listItems=[_name componentsSeparatedByString:@"_"]; + newString=[newString stringByAppendingString:[[listItems objectAtIndex:0] lowercaseString]]; + anz=[listItems count]; + for (i=1; i < anz; i++) { + newString=[newString stringByAppendingString:[[listItems objectAtIndex:i] capitalizedString]]; + } + + //#warning ergaenzen um alle components (attributes, ...) + + // Exception abfangen + NS_DURING + [self setName:newString]; + NS_HANDLER + NSLog(@"%@ in Class: EOEntity , Method: beautifyName >> error : %@",[localException name],[localException reason]); + NS_ENDHANDLER + } + + EOFLOGObjectFnStopOrCond2(@"ModelingClasses",@"EOEntity"); +*/ +} + +@end + +@implementation EOEntity (MethodSet11) + +- (NSException *)validateObjectForDelete: (id)object +{ +//OK ?? + NSArray *relationships = nil; + NSEnumerator *relEnum = nil; + EORelationship *relationship = nil; + NSMutableArray *expArray = nil; + + relationships = [self relationships]; + relEnum = [relationships objectEnumerator]; + + while ((relationship = [relEnum nextObject])) + { +//classproperties + +//rien pour nullify + if ([relationship deleteRule] == EODeleteRuleDeny) + { + if (!expArray) + expArray = [NSMutableArray arrayWithCapacity:5]; + + [expArray addObject: + [NSException validationExceptionWithFormat: + @"delete operation for relationship key %@ refused", + [relationship name]]]; + } + } + + if (expArray) + return [NSException aggregateExceptionWithExceptions:expArray]; + else + return nil; +} + +/** Retain an array of name of all EOAttributes **/ +- (NSArray*) classPropertyAttributeNames +{ + //Should be OK + if (!_classPropertyAttributeNames) + { + NSArray *classProperties = [self classProperties]; + int i, count = [classProperties count]; + Class attrClass = [EOAttribute class]; + + _classPropertyAttributeNames = [NSMutableArray new]; //or GC ? + + for (i = 0; i < count; i++) + { + EOAttribute *property = [classProperties objectAtIndex: i]; + + if ([property isKindOfClass: attrClass]) + [(NSMutableArray*)_classPropertyAttributeNames + addObject: [property name]]; + } + + EOFLOGObjectLevelArgs(@"EOEntity", @"_classPropertyAttributeNames=%@", + _classPropertyAttributeNames); + } + + return _classPropertyAttributeNames; +} + +- (NSArray*) classPropertyToManyRelationshipNames +{ + //Should be OK + if (!_classPropertyToManyRelationshipNames) + { + NSArray *classProperties = [self classProperties]; + int i, count = [classProperties count]; + Class relClass = [EORelationship class]; + + _classPropertyToManyRelationshipNames = [NSMutableArray new]; //or GC ? + + for (i = 0; i < count; i++) + { + EORelationship *property = [classProperties objectAtIndex: i]; + + if ([property isKindOfClass: relClass] + && [property isToMany]) + [(NSMutableArray*)_classPropertyToManyRelationshipNames + addObject: [property name]]; + } + } + + return _classPropertyToManyRelationshipNames; +} + +- (NSArray*) classPropertyToOneRelationshipNames +{ + //Should be OK + if (!_classPropertyToOneRelationshipNames) + { + NSArray *classProperties = [self classProperties]; + int i, count = [classProperties count]; + Class relClass = [EORelationship class]; + + _classPropertyToOneRelationshipNames = [NSMutableArray new]; //or GC ? + + for (i = 0; i 0, @"Empty relationship path"); + + //Verify when multi part path and not _relationshipPathIsToMany:path + parts = [relPath componentsSeparatedByString: @"."]; + rel = [self relationshipNamed: [parts objectAtIndex: 0]]; + + if (!rel) + { + NSEmitTODO(); //TODO + //TODO + } + else + { + NSArray *joins = [rel joins]; + int i, count = [joins count]; + + for (i = 0; i < count; i++) + { + EOJoin *join = [joins objectAtIndex: i]; + EOAttribute *attribute = [join sourceAttribute]; + + [attributes setObject: attribute + forKey: [attribute name]]; + } + } +} + +- (NSArray*) dbSnapshotKeys +{ + //OK + EOFLOGObjectFnStart(); + + if (!_dbSnapshotKeys) + { + NSArray *attributesToFetch = [self _attributesToFetch]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"attributesToFetch=%@", + attributesToFetch); + NSAssert3(!attributesToFetch + || [attributesToFetch isKindOfClass: [NSArray class]], + @"entity %@ attributesToFetch is not an NSArray but a %@\n%@", + [self name], + [attributesToFetch class], + attributesToFetch); + + ASSIGN(_dbSnapshotKeys, + [GCArray arrayWithArray: [attributesToFetch + resultsOfPerformingSelector: + @selector(name)]]); + } + + EOFLOGObjectFnStop(); + + return _dbSnapshotKeys; +} + +- (NSArray*) flattenedAttributes +{ + //OK + NSMutableArray *flattenedAttributes = [NSMutableArray array]; + NSArray *attributesToFetch = [self _attributesToFetch]; + int i, count = [attributesToFetch count]; + + NSAssert3(!attributesToFetch + || [attributesToFetch isKindOfClass: [NSArray class]], + @"entity %@ attributesToFetch is not an NSArray but a %@\n%@", + [self name], + [attributesToFetch class], + attributesToFetch); + + for (i = 0; i < count; i++) + { + EOAttribute *attribute = [attributesToFetch objectAtIndex: i]; + + if ([attribute isFlattened]) + [flattenedAttributes addObject: attribute]; + } + + return flattenedAttributes; +} + +@end + +@implementation EOEntity (EOStoredProcedures) + +- (EOStoredProcedure *)storedProcedureForOperation: (NSString *)operation +{ + return [_storedProcedures objectForKey: operation]; +} + +- (void)setStoredProcedure: (EOStoredProcedure *)storedProcedure + forOperation: (NSString *)operation +{ + [_storedProcedures setObject: storedProcedure + forKey: operation]; +} + +@end + + +@implementation EOEntity (EOPrimaryKeyGeneration) + +- (NSString *)primaryKeyRootName +{ + if (_parent) + return [_parent externalName];//mirko: [_parent primaryKeyRootName]; + + return _externalName; +} + +@end + + +@implementation EOEntity (EOEntityClassDescription) + +- (EOClassDescription *)classDescriptionForInstances +{ + EOFLOGObjectFnStart(); + +// EOFLOGObjectLevelArgs(@"EOEntity", @"in classDescriptionForInstances"); + EOFLOGObjectLevelArgs(@"EOEntity", @"_classDescription=%@", + _classDescription); + + if (!_classDescription) + { + _classDescription = [EOEntityClassDescription + entityClassDescriptionWithEntity: self]; + +//NO ? NotifyCenter addObserver:EOEntityClassDescription selector:_eoNowMultiThreaded: name:NSWillBecomeMultiThreadedNotification object:nil + } + + EOFLOGObjectFnStop(); + + return _classDescription; +} + +@end + +@implementation EOEntity (EOEntityPrivate) + +- (void)setCreateMutableObjects: (BOOL)flag +{ + if (_flags.createsMutableObjects == flag) + return; + + _flags.createsMutableObjects = flag; + +//TODO NSEmitTODO(); + + if (_flags.createsMutableObjects) + { + _attributes = [[_attributes autorelease] mutableCopy]; + _relationships = [[_relationships autorelease] mutableCopy]; + } + else + { + _attributes = [[_attributes autorelease] copy]; + _relationships = [[_relationships autorelease] copy]; + } + + NSAssert4(!_attributesToFetch + || [_attributesToFetch isKindOfClass: [NSArray class]], + @"entity %@ attributesToFetch %p is not an NSArray but a %@\n%@", + [self name], + _attributesToFetch, + [_attributesToFetch class], + _attributesToFetch); +} + +- (BOOL)createsMutableObjects +{ + return _flags.createsMutableObjects; +} + +- (void)setModel: (EOModel *)model +{ + EOFLOGObjectLevelArgs(@"EOEntity", @"setModel=%p", model); + + NSAssert4(!_attributesToFetch + || [_attributesToFetch isKindOfClass:[NSArray class]], + @"entity %@ attributesToFetch %p is not an NSArray but a %@\n%@", + [self name], + _attributesToFetch, + [_attributesToFetch class], + _attributesToFetch); + + [self _setModel: model]; +} + +- (void)setParentEntity: (EOEntity *)parent +{ + ASSIGN(_parent, parent); +} + +- (NSDictionary *)snapshotForRow: (NSDictionary *)aRow +{ + NSArray *array = [self attributesUsedForLocking]; + int i, n = [array count]; + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity: n]; + + for (i = 0; i < n; i++) + { + id key = [(EOAttribute *)[array objectAtIndex: i] name]; + + [dict setObject: [aRow objectForKey:key] forKey: key]; + } + + return dict; +} + +@end + +@implementation EOEntity (EOEntityHidden) + +/** Returns attributes by name (only attributes, not relationships) **/ +- (NSDictionary*)attributesByName +{ + EOFLOGObjectFnStart(); + + if (_attributesByName) + { + EOFLOGObjectLevelArgs(@"EOEntity", @"_attributesByName [%p] (%@)", + _attributesByName, + [_attributesByName class]); + NSAssert2((!_attributesByName + || [_attributesByName isKindOfClass: [NSDictionary class]]), + @"_attributesByName is not a NSDictionary but a %@. _attributesByName [%p]", + [_attributesByName class], + _attributesByName); + } + else + { + EOFLOGObjectLevelArgs(@"EOEntity", @"Will Rebuild attributes"); + + [self attributes]; //To rebuild + + EOFLOGObjectLevelArgs(@"EOEntity", @"_attributesByName [%p] (%@)", + _attributesByName, + [_attributesByName class]); + NSAssert2((!_attributesByName + || [_attributesByName isKindOfClass:[NSDictionary class]]), + @"_attributesByName is not a NSDictionary but a %@. _attributesByName [%p]", + [_attributesByName class], + _attributesByName); + } + + EOFLOGObjectFnStop(); + + return _attributesByName; +} + +- (NSDictionary*)relationshipsByName +{ + if (!_relationshipsByName) + { + [self relationships]; //To rebuild + } + return _relationshipsByName; +} + +- (NSArray*) _allFetchSpecifications +{ + //OK + NSDictionary *fetchSpecificationDictionary = + [self _fetchSpecificationDictionary]; + NSArray *fetchSpecValues = [fetchSpecificationDictionary allValues]; + + return fetchSpecValues; +} + +- (NSDictionary*) _fetchSpecificationDictionary +{ + //OK + return _fetchSpecificationDictionary; +} + +- (void) _loadEntity +{ + //TODO + [self notImplemented: _cmd]; +} + +- (id) parentRelationship +{ + //TODO + return [self notImplemented: _cmd]; +} + +- (int) _numberOfRelationships +{ + //OK + return [[self relationships] count]; +} + +- (BOOL) _hasReadOnlyAttributes +{ + //OK + BOOL hasReadOnlyAttributes = NO; + NSArray *attributes = [self attributes]; + int i, count=[attributes count]; + + for (i = 0; !hasReadOnlyAttributes && i < count; i++) + hasReadOnlyAttributes = [[attributes objectAtIndex: i] isReadOnly]; + + return hasReadOnlyAttributes; +} + +- (NSArray*) writableDBSnapshotKeys +{ + //OK + NSMutableArray *writableDBSnapshotKeys = [NSMutableArray array]; + + if (![self isReadOnly]) + { + NSArray *attributesToFetch = [self _attributesToFetch]; + int i, count = [attributesToFetch count]; + + NSAssert3(!attributesToFetch + || [attributesToFetch isKindOfClass: [NSArray class]], + @"entity %@ attributesToFetch is not an NSArray but a %@\n%@", + [self name], + [attributesToFetch class], + attributesToFetch); + + for (i = 0; i < count; i++) + { + EOAttribute *attribute = [attributesToFetch objectAtIndex: i]; + + if (![attribute isReadOnly]) + [writableDBSnapshotKeys addObject: [attribute name]]; + } + } + + return writableDBSnapshotKeys; +} + +- (NSArray*) rootAttributesUsedForLocking +{ + //OK ? + NSMutableArray *rootAttributesUsedForLocking = [NSMutableArray array]; + NSArray *attributesUsedForLocking = [self attributesUsedForLocking]; + int i, count = [attributesUsedForLocking count]; + + for (i = 0; i < count; i++) + { + EOAttribute *attribute = [attributesUsedForLocking objectAtIndex: i]; + if (![attribute isDerived]) + [rootAttributesUsedForLocking addObject: attribute]; + } + + return rootAttributesUsedForLocking; +} + +- (BOOL) isSubEntityOf: (id)param0 +{ + //TODO + [self notImplemented: _cmd]; + return NO; +} + +- (id) initObject: (id)param0 + editingContext: (id)param1 + globalID: (id)param2 +{ + //TODO + return [self notImplemented: _cmd]; +} + +- (id) allocBiggestObjectWithZone: (NSZone*)zone +{ + //TODO + return [self notImplemented: _cmd]; +} + +- (Class) _biggestClass +{ + //OK + Class biggestClass = Nil; + + biggestClass = [self classForObjectWithGlobalID: nil]; + + return biggestClass; +} + +- (NSArray*) relationshipsPlist +{ + //OK + NSMutableArray *relsPlist; + + if (_flags.relationshipsIsLazy) + { + relsPlist = _relationships; + } + else + { + NSArray *relationships; + int relCount; + + relsPlist = [NSMutableArray array]; + relationships = [self relationships]; + relCount = [relationships count]; + + if (relCount > 0) + { + int i; + + for (i = 0; i < relCount; i++) + { + NSMutableDictionary *relPlist = [NSMutableDictionary dictionary]; + EORelationship *rel = [relationships objectAtIndex: i]; + + [rel encodeIntoPropertyList: relPlist]; + [relsPlist addObject: relPlist]; + } + } + } + + return relsPlist; +} + +- (id) rootParent +{ + id prevParent = self; + id parent = self; + + while (parent) + { + prevParent = parent; + parent = [prevParent parentEntity]; + } + + return prevParent; +} + +- (void) _setParent: (id)param0 +{ + //TODO + [self notImplemented: _cmd]; +} + +- (NSArray*) _hiddenRelationships +{ + //OK + if (!_hiddenRelationships) + _hiddenRelationships = [NSMutableArray new]; + + return _hiddenRelationships; +} + +- (NSArray*) _propertyNames +{ + //OK + NSMutableArray *propertyNames = nil; + NSArray *attributes = [self attributes]; + NSArray *attributeNames = [attributes resultsOfPerformingSelector: + @selector(name)]; + NSArray *relationships = [self relationships]; + NSArray *relationshipNames = [relationships resultsOfPerformingSelector: + @selector(name)]; + + propertyNames = [NSMutableArray arrayWithArray: attributeNames]; + [propertyNames addObjectsFromArray: relationshipNames]; + + return propertyNames; +} + +- (id) _flattenAttribute: (id)param0 + relationshipPath: (id)param1 + currentAttributes: (id)param2 +{ + //TODO + return [self notImplemented: _cmd]; +} + +- (NSString*) snapshotKeyForAttributeName: (NSString*)attributeName +{ + NSString *attName = [self _flattenedAttNameToSnapshotKeyMapping]; + + if (attName) + { + NSEmitTODO(); //TODO + [self notImplemented: _cmd]; + } + else + attName = attributeName; //TODO-VERIFY + + return attName; +} + +- (id) _flattenedAttNameToSnapshotKeyMapping +{ + // NSArray *attributesToSave = [self _attributesToSave]; + + //NSEmitTODO(); //TODO + + return nil; //[self notImplemented:_cmd]; //TODO +} + +- (EOMKKDSubsetMapping*) _snapshotToAdaptorRowSubsetMapping +{ + if (!_snapshotToAdaptorRowSubsetMapping) + { + EOMKKDInitializer *snapshotDictionaryInitializer = + [self _snapshotDictionaryInitializer]; + EOMKKDInitializer *adaptorDictionaryInitializer = + [self _adaptorDictionaryInitializer]; + EOMKKDSubsetMapping *subsetMapping = + [snapshotDictionaryInitializer + subsetMappingForSourceDictionaryInitializer: adaptorDictionaryInitializer]; + + ASSIGN(_snapshotToAdaptorRowSubsetMapping,subsetMapping); + } + + return _snapshotToAdaptorRowSubsetMapping; +} + +- (EOMutableKnownKeyDictionary*) _dictionaryForPrimaryKey +{ + //OK + EOMKKDInitializer *primaryKeyDictionaryInitializer = + [self _primaryKeyDictionaryInitializer]; + EOMutableKnownKeyDictionary *dictionaryForPrimaryKey = + [EOMutableKnownKeyDictionary dictionaryWithInitializer: + primaryKeyDictionaryInitializer]; + + return dictionaryForPrimaryKey; +} + +- (EOMutableKnownKeyDictionary*) _dictionaryForProperties +{ + //OK + EOMKKDInitializer *propertyDictionaryInitializer = nil; + EOMutableKnownKeyDictionary *dictionaryForProperties = nil; + + EOFLOGObjectFnStart(); + + propertyDictionaryInitializer = [self _propertyDictionaryInitializer]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"propertyDictionaryInitializer=%@", + propertyDictionaryInitializer); + + dictionaryForProperties = [EOMutableKnownKeyDictionary + dictionaryWithInitializer: + propertyDictionaryInitializer]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"dictionaryForProperties=%@", + dictionaryForProperties); + + EOFLOGObjectFnStop(); + + return dictionaryForProperties; +} + +- (NSArray*) _relationshipsToFaultForRow: (NSDictionary*)row +{ + NSMutableArray *rels = [NSMutableArray array]; + NSArray *classProperties = [self classProperties]; + int i, count = [classProperties count]; + + for (i = 0; i < count; i++) + { + EORelationship *classProperty = [classProperties objectAtIndex: i]; + + if ([classProperty isKindOfClass: [EORelationship class]]) + { + EORelationship *relsubs = [classProperty + _substitutionRelationshipForRow: row]; + + [rels addObject: relsubs]; + } + } + + return rels; +} + +- (NSArray*) _classPropertyAttributes +{ + //OK + //IMPROVE We can improve this by caching the result.... + NSMutableArray *classPropertyAttributes = [NSMutableArray array]; + //Get classProperties (EOAttributes + EORelationships) + NSArray *classProperties = [self classProperties]; + int i, count = [classProperties count]; + + for (i = 0; i < count; i++) + { + id object = [classProperties objectAtIndex: i]; + + if ([object isKindOfClass: [EOAttribute class]]) + [classPropertyAttributes addObject: object]; + } + + return classPropertyAttributes; +} + +- (NSArray*) _attributesToSave +{ + //Near OK + EOFLOGObjectLevelArgs(@"EOEntity", + @"START Entity _attributesToSave entityname=%@", + [self name]); + + if (!_attributesToSave) + { + NSMutableArray *attributesToSave = [GCMutableArray array]; + NSArray *attributesToFetch = [self _attributesToFetch]; + int i, count = [attributesToFetch count]; + + NSAssert3(!attributesToFetch + || [attributesToFetch isKindOfClass: [NSArray class]], + @"entity %@ attributesToFetch is not an NSArray but a %@\n%@", + [self name], + [_attributesToFetch class], + _attributesToFetch); + + for (i = 0; i < count; i++) + { + EOAttribute *attribute = [attributesToFetch objectAtIndex: i]; + BOOL isFlattened = [attribute isFlattened]; + + if (!isFlattened) + [attributesToSave addObject: attribute]; + } + ASSIGN(_attributesToSave, attributesToSave); + } + + EOFLOGObjectLevelArgs(@"EOEntity", @"STOP Entity _attributesToSave entityname=%@ attrs:%@", + [self name], _attributesToSave); + + return _attributesToSave; +} + +//sorted by name attributes +- (NSArray*) _attributesToFetch +{ + //Seems OK + EOFLOGObjectLevelArgs(@"EOEntity", + @"START Entity _attributesToFetch entityname=%@", + [self name]); + EOFLOGObjectLevelArgs(@"EOEntity", @"AttributesToFetch:%p", + _attributesToFetch); + EOFLOGObjectLevelArgs(@"EOEntity", @"AttributesToFetch:%@", + _attributesToFetch); + + NSAssert2(!_attributesToFetch + || [_attributesToFetch isKindOfClass: [NSArray class]], + @"entity %@ attributesToFetch is not an NSArray but a %@", + [self name], + [_attributesToFetch class]); + + if (!_attributesToFetch) + { + NSMutableDictionary *attributesDict = [NSMutableDictionary dictionary]; + NS_DURING + { + int iArray = 0; + NSArray *arrays[] = { [self attributesUsedForLocking], + [self primaryKeyAttributes], + [self classProperties], + [self relationships] }; + + _attributesToFetch = [[GCMutableArray array] retain]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"Entity %@ - _attributesToFetch %p [RC=%d]:%@", + [self name], + _attributesToFetch, + [_attributesToFetch retainCount], + _attributesToFetch); + + for (iArray = 0; iArray < 4; iArray++) + { + int i, count = 0; + + EOFLOGObjectLevelArgs(@"EOEntity", @"Entity %@ - arrays[iArray]:%@", + [self name], arrays[iArray]); + + count = [arrays[iArray] count]; + + for (i = 0; i < count; i++) + { + id property = [arrays[iArray] objectAtIndex: i]; + NSString *propertyName = [(EOAttribute*)property name]; + + //VERIFY + EOFLOGObjectLevelArgs(@"EOEntity", + @"propertyName=%@ - property=%@", + propertyName, property); + + if ([property isKindOfClass: [EOAttribute class]]) + { + EOAttribute *attribute = property; + + if ([attribute isFlattened]) + { + attribute = [[attribute _definitionArray] + objectAtIndex: 0]; + propertyName = [attribute name]; + } + } + + if ([property isKindOfClass: [EORelationship class]]) + { + [self _addAttributesToFetchForRelationshipPath: + [(EORelationship*)property relationshipPath] + atts: attributesDict]; + } + else if ([property isKindOfClass: [EOAttribute class]]) + { + [attributesDict setObject: property + forKey: propertyName]; + } + else + { + NSEmitTODO(); //TODO + } + } + } + } + NS_HANDLER + { + NSDebugMLog(@"Exception: %@",localException); + [localException raise]; + } + NS_ENDHANDLER; + NS_DURING + { + NSDebugMLog(@"Attributes to fetch classes %@", + [_attributesToFetch resultsOfPerformingSelector: + @selector(class)]); + + [_attributesToFetch addObjectsFromArray: [attributesDict allValues]]; + + NSDebugMLog(@"Attributes to fetch classes %@", + [_attributesToFetch resultsOfPerformingSelector: + @selector(class)]); + + [_attributesToFetch sortUsingSelector: @selector(eoCompareOnName:)]; //Very important to have always the same order. + } + NS_HANDLER + { + NSDebugMLog(@"Exception: %@",localException); + [localException raise]; + } + NS_ENDHANDLER; + }; + + NSAssert3(!_attributesToFetch + || [_attributesToFetch isKindOfClass: [NSArray class]], + @"Entity %@: _attributesToFetch is not an NSArray but a %@\n%@", + [self name], + [_attributesToFetch class], + _attributesToFetch); + + EOFLOGObjectLevelArgs(@"EOEntity", @"Stop Entity %@ - _attributesToFetch %p [RC=%d]:%@", + [self name], + _attributesToFetch, + [_attributesToFetch retainCount], + _attributesToFetch); + + return _attributesToFetch; +} + +- (EOMKKDInitializer*) _adaptorDictionaryInitializer +{ + //OK + EOFLOGObjectLevelArgs(@"EOEntity", @"Start _adaptorDictionaryInitializer=%@", + _adaptorDictionaryInitializer); + + if (!_adaptorDictionaryInitializer) + { + NSArray *attributesToFetch = [self _attributesToFetch]; + NSArray *attributeToFetchNames = [attributesToFetch + resultsOfPerformingSelector: + @selector(name)]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"attributeToFetchNames=%@", + attributeToFetchNames); + + NSAssert3(!attributesToFetch + || [attributesToFetch isKindOfClass: [NSArray class]], + @"entity %@ attributesToFetch is not an NSArray but a %@\n%@", + [self name], + [attributesToFetch class], + attributesToFetch); + NSAssert1([attributesToFetch count] > 0, + @"No Attributes to fetch in entity %@", [self name]); + NSAssert1([attributeToFetchNames count] > 0, + @"No Attribute names to fetch in entity %@", [self name]); + + EOFLOGObjectLevelArgs(@"EOEntity", @"entity named %@: attributeToFetchNames=%@", + [self name], + attributeToFetchNames); + + ASSIGN(_adaptorDictionaryInitializer, + [EOMutableKnownKeyDictionary initializerFromKeyArray: + attributeToFetchNames]); + + EOFLOGObjectLevelArgs(@"EOEntity", @"entity named %@ _adaptorDictionaryInitializer=%@", + [self name], + _adaptorDictionaryInitializer); + } + + EOFLOGObjectLevelArgs(@"EOEntity", @"Stop _adaptorDictionaryInitializer=%p", + _adaptorDictionaryInitializer); + EOFLOGObjectLevelArgs(@"EOEntity", @"Stop _adaptorDictionaryInitializer=%@", + _adaptorDictionaryInitializer); + + return _adaptorDictionaryInitializer; +} + +- (EOMKKDInitializer*) _snapshotDictionaryInitializer +{ + if (!_snapshotDictionaryInitializer) + { + NSArray *dbSnapshotKeys = [self dbSnapshotKeys]; + + ASSIGN(_snapshotDictionaryInitializer, + [EOMutableKnownKeyDictionary initializerFromKeyArray: + dbSnapshotKeys]); + } + + return _snapshotDictionaryInitializer; +} + +- (EOMKKDInitializer*) _primaryKeyDictionaryInitializer +{ + //OK + if (!_primaryKeyDictionaryInitializer) + { + NSArray *primaryKeyAttributeNames = [self primaryKeyAttributeNames]; + + NSAssert1([primaryKeyAttributeNames count] > 0, + @"No primaryKeyAttributeNames in entity %@", [self name]); + + EOFLOGObjectLevelArgs(@"EOEntity", @"entity named %@: primaryKeyAttributeNames=%@", + [self name], + primaryKeyAttributeNames); + + _primaryKeyDictionaryInitializer = [EOMKKDInitializer + newWithKeyArray: + primaryKeyAttributeNames]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"entity named %@: _primaryKeyDictionaryInitializer=%@", + [self name], + _primaryKeyDictionaryInitializer); + } + + return _primaryKeyDictionaryInitializer; +} + +- (EOMKKDInitializer*) _propertyDictionaryInitializer +{ + //OK + // If not already built, built it + if (!_propertyDictionaryInitializer) + { + // Get class properties (EOAttributes + EORelationships) + NSArray *classProperties = [self classProperties]; + NSArray *classPropertyNames = + [classProperties resultsOfPerformingSelector: @selector(name)]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"entity %@ classPropertyNames=%@", + [self name], classPropertyNames); + + NSAssert1([classProperties count] > 0, + @"No classProperties in entity %@", [self name]); + NSAssert1([classPropertyNames count] > 0, + @"No classPropertyNames in entity %@", [self name]); + + //Build the multiple known key initializer + _propertyDictionaryInitializer = [EOMKKDInitializer + newWithKeyArray: classPropertyNames]; + } + + return _propertyDictionaryInitializer; +} + +- (void) _setModel: (EOModel *)model +{ + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOEntity", @"_setModel=%p", model); + ASSIGN(_model, model); + + EOFLOGObjectFnStop(); +} + +- (void) _setIsEdited +{ + EOFLOGObjectLevelArgs(@"EOEntity", @"START entity name=%@", [self name]); + + NSAssert4(!_attributesToFetch + || [_attributesToFetch isKindOfClass: [NSArray class]], + @"entity %@ attributesToFetch %p is not an NSArray but a %@\n%@", + [self name], + _attributesToFetch, + [_attributesToFetch class], + _attributesToFetch); + + //Destroy cached ivar + EOFLOGObjectLevelArgs(@"EOEntity", @"_classPropertyNames: void:%p [%p] %s", + (void*)nil, (void*)_classPropertyNames, + (_classPropertyNames ? "Not NIL" : "NIL")); + DESTROY(_classPropertyNames); + + EOFLOGObjectLevelArgs(@"EOEntity", @"_primaryKeyAttributeNames: %p %s", + (void*)_primaryKeyAttributeNames, + (_primaryKeyAttributeNames ? "Not NIL" : "NIL")); + DESTROY(_primaryKeyAttributeNames); + + EOFLOGObjectLevelArgs(@"EOEntity", @"_classPropertyAttributeNames: %p %s", + _classPropertyAttributeNames, + (_classPropertyAttributeNames ? "Not NIL" : "NIL")); + DESTROY(_classPropertyAttributeNames); + + EOFLOGObjectLevelArgs(@"EOEntity", @"_classPropertyToOneRelationshipNames: %p %s", + _classPropertyToOneRelationshipNames, + (_classPropertyToOneRelationshipNames ? "Not NIL" : "NIL")); + DESTROY(_classPropertyToOneRelationshipNames); + + EOFLOGObjectLevelArgs(@"EOEntity", @"_classPropertyToManyRelationshipNames: %p %s", + _classPropertyToManyRelationshipNames, + (_classPropertyToManyRelationshipNames ? "Not NIL" : "NIL")); + DESTROY(_classPropertyToManyRelationshipNames); + + EOFLOGObjectLevelArgs(@"EOEntity", @"_attributesToFetch: %p %s", + _attributesToFetch, + (_attributesToFetch ? "Not NIL" : "NIL")); + DESTROY(_attributesToFetch); + + EOFLOGObjectLevelArgs(@"EOEntity", @"_dbSnapshotKeys: %p %s", + _dbSnapshotKeys, (_dbSnapshotKeys ? "Not NIL" : "NIL")); + DESTROY(_dbSnapshotKeys); + + EOFLOGObjectLevelArgs(@"EOEntity", @"_attributesToSave: %p %s", + _attributesToSave, (_attributesToSave ? "Not NIL" : "NIL")); + DESTROY(_attributesToSave); + + EOFLOGObjectLevelArgs(@"EOEntity", @"_propertiesToFault: %p %s", + _propertiesToFault, (_propertiesToFault ? "Not NIL" : "NIL")); + DESTROY(_propertiesToFault); + + EOFLOGObjectLevelArgs(@"EOEntity", @"_adaptorDictionaryInitializer: %p %s", + _adaptorDictionaryInitializer, + (_adaptorDictionaryInitializer ? "Not NIL" : "NIL")); + DESTROY(_adaptorDictionaryInitializer); + + EOFLOGObjectLevelArgs(@"EOEntity", @"_snapshotDictionaryInitializer: %p %s", + _snapshotDictionaryInitializer, + (_snapshotDictionaryInitializer ? "Not NIL" : "NIL")); + DESTROY(_snapshotDictionaryInitializer); + + EOFLOGObjectLevelArgs(@"EOEntity",@"_primaryKeyDictionaryInitializer: %p %s", + _primaryKeyDictionaryInitializer, + (_primaryKeyDictionaryInitializer ? "Not NIL" : "NIL")); + DESTROY(_primaryKeyDictionaryInitializer); + + EOFLOGObjectLevelArgs(@"EOEntity",@"_propertyDictionaryInitializer: %p %s", + _propertyDictionaryInitializer, + (_propertyDictionaryInitializer ? "Not NIL" : "NIL")); + DESTROY(_propertyDictionaryInitializer); + + //TODO call _flushCache on each attr + NSAssert4(!_attributesToFetch + || [_attributesToFetch isKindOfClass: [NSArray class]], + @"entity %@ attributesToFetch %p is not an NSArray but a %@\n%@", + [self name], + _attributesToFetch, + [_attributesToFetch class], + _attributesToFetch); + + EOFLOGObjectLevelArgs(@"EOEntity", @"STOP%s", ""); +} + +@end + +@implementation EOEntity (EOKeyGlobalID) + +- (id) globalIDForRow: (NSDictionary*)row + isFinal: (BOOL)isFinal +{ + EOKeyGlobalID *globalID = nil; + NSArray *primaryKeyAttributeNames = nil; + int count = 0; + + NSAssert([row count] > 0, @"Empty Row."); + + primaryKeyAttributeNames = [self primaryKeyAttributeNames]; + count = [primaryKeyAttributeNames count]; + { + id keyArray[count]; + int i; + + memset(keyArray, 0, sizeof(id) * count); + + for (i = 0; i < count; i++) + keyArray[i] = [row objectForKey: + [primaryKeyAttributeNames objectAtIndex: i]]; + + globalID = [EOKeyGlobalID globalIDWithEntityName: [self name] + keys: keyArray + keyCount: count + zone: [self zone]]; + } + + //NSEmitTODO(); //TODO + //TODO isFinal ?? + + return globalID; +}; + +- (EOGlobalID *)globalIDForRow: (NSDictionary *)row +{ + EOGlobalID *gid = [self globalIDForRow: row + isFinal: NO]; + + NSAssert(gid, @"No gid"); +//TODO +/* +pas toutjur: la suite editingc objectForGlobalID: +EODatabaseContext snapshotForGlobalID: + if no snpashot: + { +database recordSnapshot:forGlobalID: +self classDescriptionForInstances +createInstanceWithEditingContext:globalID:zone: + } +*/ + return gid; +} + +-(Class)classForObjectWithGlobalID: (EOKeyGlobalID*)globalID +{ + //near OK + EOFLOGObjectFnStart(); + + //TODO:use globalID ?? + if (!_classForInstances) + { + NSString *className; + Class objectClass; + + className = [self className]; + EOFLOGObjectLevelArgs(@"EOEntity", @"className=%@", className); + + objectClass = NSClassFromString(className); + + if (!objectClass) + { + NSLog(@"Error: No class named %@", className); + } + else + { + EOFLOGObjectLevelArgs(@"EOEntity", @"objectClass=%@", objectClass); + ASSIGN(_classForInstances, objectClass); + } + } + + EOFLOGObjectFnStop(); + + return _classForInstances; +} + +- (NSDictionary *)primaryKeyForGlobalID: (EOKeyGlobalID *)gid +{ + //OK + NSMutableDictionary *dictionaryForPrimaryKey = nil; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOEntity", @"gid=%@", gid); + + if ([gid isKindOfClass: [EOKeyGlobalID class]]) //if ([gid isFinal])//?? or class test ??//TODO + { + NSArray *primaryKeyAttributeNames = [self primaryKeyAttributeNames]; + int count = [primaryKeyAttributeNames count]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"primaryKeyAttributeNames=%@", + primaryKeyAttributeNames); + + if (count > 0) + { + int i; + id *gidkeyValues = [gid keyValues]; + + if (gidkeyValues) + { + dictionaryForPrimaryKey = [self _dictionaryForPrimaryKey]; + + NSAssert1(dictionaryForPrimaryKey, + @"No dictionaryForPrimaryKey in entity %@", + [self name]); + EOFLOGObjectLevelArgs(@"EOEntity", @"dictionaryForPrimaryKey=%@", + dictionaryForPrimaryKey); + + for (i = 0; i < count; i++) + { + id key = [primaryKeyAttributeNames objectAtIndex: i]; + + [dictionaryForPrimaryKey setObject: gidkeyValues[i] + forKey: key]; + } + } + } + } + else + NSLog(@"EOEntity (%@): primaryKey is *nil* for globalID = %@", _name, gid); + + EOFLOGObjectLevelArgs(@"EOEntity", @"dictionaryForPrimaryKey=%@", + dictionaryForPrimaryKey); + + EOFLOGObjectFnStop(); + + return dictionaryForPrimaryKey; +} + +@end + +@implementation EOEntity (EOEntityRelationshipPrivate) + +- (EORelationship*) _inverseRelationshipPathForPath: (NSString*)path +{ + //TODO + return [self notImplemented: _cmd]; +} + +- (NSDictionary*) _keyMapForIdenticalKeyRelationshipPath: (NSString*)path +{ + NSDictionary *keyMap = nil; + EORelationship *rel; + NSMutableArray *sourceAttributeNames = [NSMutableArray array]; + NSMutableArray *destinationAttributeNames = [NSMutableArray array]; + NSArray *joins; + int i, count = 0; + + //use path,not only one element ? + rel = [self relationshipNamed: path]; + joins = [rel joins]; + count = [joins count]; + + for (i = 0; i < count; i++) + { + EOJoin *join = [joins objectAtIndex: i]; + EOAttribute *sourceAttribute = [join sourceAttribute]; + EOAttribute *destinationAttribute = + [self _mapAttribute:sourceAttribute + toDestinationAttributeInLastComponentOfRelationshipPath: path]; + + [sourceAttributeNames addObject: [sourceAttribute name]]; + [destinationAttributeNames addObject: [destinationAttribute name]]; + } + + keyMap = [NSDictionary dictionaryWithObjectsAndKeys: + sourceAttributeNames, @"sourceKeys", + destinationAttributeNames, @"destinationKeys", + nil, nil]; + //return something like {destinationKeys = (code); sourceKeys = (languageCode); } + + return keyMap; +} + +- (EOAttribute*) _mapAttribute: (EOAttribute*)attribute +toDestinationAttributeInLastComponentOfRelationshipPath: (NSString*)path +{ + NSArray *components = nil; + EORelationship *rel = nil; + NSArray *sourceAttributes = nil; + NSArray *destinationAttributes = nil; + EOEntity *destinationEntity = nil; + + NSAssert(attribute, @"No attribute"); + NSAssert(path, @"No path"); + NSAssert([path length] > 0, @"Empty path"); + + components = [path componentsSeparatedByString: @"."]; + NSAssert([components count] > 0, @"Empty components array"); + + rel = [self relationshipNamed: [components lastObject]]; + sourceAttributes = [rel sourceAttributes]; + destinationAttributes = [rel destinationAttributes]; + destinationEntity = [rel destinationEntity]; + + NSEmitTODO(); //TODO + + return [self notImplemented: _cmd]; +} + +- (BOOL) _relationshipPathIsToMany: (NSString*)relPath +{ + //Seems OK + BOOL isToMany = NO; + NSArray *parts = [relPath componentsSeparatedByString: @"."]; + EOEntity *entity = self; + int i, count = [parts count]; + + for (i = 0 ; !isToMany && i < count; i++) //VERIFY Stop when finding the 1st isToMany ? + { + EORelationship *rel = [entity relationshipNamed: + [parts objectAtIndex: i]]; + + isToMany = [rel isToMany]; + + if (!isToMany) + entity = [rel destinationEntity]; + } + + return isToMany; +} + +- (BOOL) _relationshipPathHasIdenticalKeys: (id)param0 +{ + [self notImplemented: _cmd]; + return NO; +} + +- (NSDictionary *)_keyMapForRelationshipPath: (NSString *)path +{ + //NearOK + NSMutableArray *sourceKeys = [NSMutableArray array]; + NSMutableArray *destinationKeys = [NSMutableArray array]; + NSArray *attributesToFetch = [self _attributesToFetch]; //Use It !! + EORelationship *relationship = [self anyRelationshipNamed: path]; //?? iterate on path ? //TODO + + NSEmitTODO(); //TODO + + if (relationship) + { + NSArray *joins = [relationship joins]; + int i, count = [joins count]; + + for(i = 0; i < count; i++) + { + EOJoin *join = [joins objectAtIndex: i]; + EOAttribute *sourceAttribute = [join sourceAttribute]; + EOAttribute *destinationAttribute = [join destinationAttribute]; + + [sourceKeys addObject: [sourceAttribute name]]; + [destinationKeys addObject: [destinationAttribute name]]; + } + } + + return [NSDictionary dictionaryWithObjectsAndKeys: + sourceKeys, @"sourceKeys", + destinationKeys, @"destinationKeys", + nil]; +//{destinationKeys = (code); sourceKeys = (countryCode); } +} + +@end + + +@implementation EOEntity (EOEntitySQLExpression) + +- (NSString*) valueForSQLExpression: (EOSQLExpression*)sqlExpression +{ + return [self notImplemented: _cmd]; //TODO +} + ++ (NSString*) valueForSQLExpression: (EOSQLExpression*)sqlExpression +{ + return [self notImplemented: _cmd]; //TODO +} + +@implementation EOEntity (EOEntityPrivateXX) + +- (EOExpressionArray*) _parseDescription: (NSString*)description + isFormat: (BOOL)isFormat + arguments: (char*)param2 +{ +// definition = "(((text(code) || ' ') || upper(abbreviation)) || ' ')"; + EOExpressionArray *expressionArray = nil; + const char *s = NULL; + const char *start = NULL; + id objectToken = nil; + id pool = nil; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOEntity", @"expression=%@", description); + + expressionArray = [[EOExpressionArray new] autorelease]; + s = [description cString]; + + if (s) + { + pool = [NSAutoreleasePool new]; + NS_DURING + { + /* Divide the expression string in alternating substrings that obey the + following simple grammar: + + I = [a-zA-Z0-9@_#]([a-zA-Z0-9@_.#$])+ + O = \'.*\' | \".*\" | [^a-zA-Z0-9@_#]+ + S -> I S | O S | nothing + */ + while (s && *s) + { + /* Determines an I token. */ + if (isalnum(*s) || *s == '@' || *s == '_' || *s == '#') + { + EOExpressionArray *expr = nil; + + start = s; + + for (++s; *s; s++) + if (!isalnum(*s) && *s != '@' && *s != '_' + && *s != '.' && *s != '#' && *s != '$') + break; + + objectToken = [NSString stringWithCString:start + length: (unsigned)(s - start)]; + + expr = [self _parsePropertyName: objectToken]; + + if (expr) + objectToken = expr; + + EOFLOGObjectLevelArgs(@"EOEntity", @"addObject:%@", + objectToken); + + [expressionArray addObject: objectToken]; + } + + /* Determines an O token. */ + start = s; + for (; *s && !isalnum(*s) && *s != '@' && *s != '_' && *s != '#'; + s++) + { + if (*s == '\'' || *s == '"') + { + char quote = *s; + + for (++s; *s; s++) + if (*s == quote) + break; + else if (*s == '\\') + s++; /* Skip the escaped characters */ + + if (!*s) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: unterminated character string", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + } + } + + if (s != start) + { + objectToken = [NSString stringWithCString: start + length: (unsigned)(s - start)]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"addObject:%@", + objectToken); + + [expressionArray addObject: objectToken]; + } + } + } + NS_HANDLER + { + [localException retain]; + NSLog(@"exception in EOEntity _parseDescription:isFormat:arguments:"); + NSLog(@"exception=%@", localException); + + [pool release];//Release the pool ! + [localException autorelease]; + [localException raise]; + } + NS_ENDHANDLER; + [pool release]; + } + + // return nil if expressionArray is empty + if ([expressionArray count] == 0) + expressionArray = nil; + // if expressionArray contains only one element and this element is a expressionArray, use it (otherwise, isFlatten will not be accurate) + else if ([expressionArray count] == 1) + { + id expr = [expressionArray lastObject]; + + if ([expr isKindOfClass: [EOExpressionArray class]]) + expressionArray = expr; + } + + EOFLOGObjectLevelArgs(@"EOEntity", + @"expressionArray=%@\nexpressionArray count=%d isFlattened=%s\n", + expressionArray, + [expressionArray count], + ([expressionArray isFlattened] ? "YES" : "NO")); + + return expressionArray; +} + +- (EOExpressionArray*) _parseRelationshipPath: (NSString*)path +{ + //Near OK quotationPlace.quotationPlaceLabels + EOEntity *entity = self; + EOExpressionArray *expressionArray = nil; + NSArray *components = nil; + int i, count = 0; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOEntity",@"self=%p (name=%@) path=%@", + self,[self name],path); + + NSAssert1([path length] > 0, @"Path is empty (%p)", path); + + expressionArray = [EOExpressionArray expressionArrayWithPrefix: nil + infix: @"." + suffix: nil]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"self=%p expressionArray=%@", + self, expressionArray); + + components = [path componentsSeparatedByString: @"."]; + count = [components count]; + + for (i = 0; i < count; i++) + { + NSString *part = [components objectAtIndex: i]; + EORelationship *relationship; + + NSAssert1([part length] > 0, @"part is empty (path=%@)", path); + relationship = [entity anyRelationshipNamed: part]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"part=%@ relationship=%@", + part, relationship); + + if (relationship) + { + NSAssert2([relationship isKindOfClass: [EORelationship class]], + @"relationship is not a EORelationship but a %@. relationship:\n%@", + [relationship class], + relationship); + + if ([relationship isFlattened]) + { + NSEmitTODO(); //TODO + [self notImplemented: _cmd];//TODO + } + else + { + [expressionArray addObject: relationship]; + } + + entity = [relationship destinationEntity]; + } + else + { + NSDebugMLog(@"self %p name=%@: relationship \"%@\" used in \"%@\" doesn't exist in entity %@", + self, + [self name], + path, + part, + entity); + + //EOF don't throw exception. But we do ! + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: relationship \"%@\" used in \"%@\" doesn't exist in entity %@", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + path, + part, + entity]; + } + } + EOFLOGObjectLevelArgs(@"EOEntity", @"self=%p expressionArray=%@", + self, expressionArray); + + // return nil if expressionArray is empty + if ([expressionArray count] == 0) + expressionArray = nil; + // if expressionArray contains only one element and this element is a expressionArray, use it (otherwise, isFlatten will not be accurate) + else if ([expressionArray count] == 1) + { + id expr = [expressionArray lastObject]; + + if ([expr isKindOfClass: [EOExpressionArray class]]) + expressionArray = expr; + } + + EOFLOGObjectLevelArgs(@"EOEntity", @"self=%p expressionArray=%@", + self, expressionArray); + + EOFLOGObjectFnStop(); + + return expressionArray; +} + +- (id) _parsePropertyName: (NSString*)propertyName +{ + EOEntity *entity = self; + EOExpressionArray *expressionArray = nil; + NSArray *components = nil; + int i, count = 0; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOEntity", @"self=%p self name=%@ propertyName=%@", + self, [self name], propertyName); + + expressionArray = [EOExpressionArray expressionArrayWithPrefix: nil + infix: @"." + suffix: nil]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"self=%p expressionArray=%@", + self, expressionArray); + + components = [propertyName componentsSeparatedByString: @"."]; + count = [components count]; + + for (i = 0; i < count; i++) + { + NSString *part = [components objectAtIndex: i]; + EORelationship *relationship = [entity anyRelationshipNamed: part]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"self=%p entity name=%@ part=%@ relationship=%@ relationship name=%@", + self, [entity name], part, relationship, + [relationship name]); + + if (relationship) + { + NSAssert2([relationship isKindOfClass: [EORelationship class]], + @"relationship is not a EORelationship but a %@. relationship:\n%@", + [relationship class], + relationship); + + if ([relationship isFlattened]) + { + NSEmitTODO(); //TODO + [self notImplemented: _cmd];//TODO + } + else + { + EOFLOGObjectLevelArgs(@"EOEntity",@"self=%p expressionArray addObject=%@ (name=%@)", + self, relationship, [relationship name]); + + [expressionArray addObject: relationship]; + } + + entity = [relationship destinationEntity]; + } + else + { + EOAttribute *attribute = [entity anyAttributeNamed: part]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"self=%p entity name=%@ part=%@ attribute=%@ attribute name=%@", + self, [entity name], part, attribute, + [attribute name]); + + if (attribute) + [expressionArray addObject: attribute]; + else if (i < (count - 1)) + { + //EOF don't throw exception ? But we do ! + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: attribute \"%@\" used in \"%@\" doesn't exist in entity %@", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + propertyName, + part, + entity]; + } + } + } + + EOFLOGObjectLevelArgs(@"EOEntity", @"self=%p expressionArray=%@", + self, expressionArray); + // return nil if expression is empty + + if ([expressionArray count] == 0) + expressionArray = nil; + else if ([expressionArray count] == 1) + expressionArray = [expressionArray objectAtIndex: 0]; + + EOFLOGObjectLevelArgs(@"EOEntity", @"self=%p expressionArray=\"%@\"", + self, expressionArray); + + EOFLOGObjectFnStop(); + + return expressionArray; +} + +@end + +@implementation EOEntityClassDescription + ++ (EOEntityClassDescription*)entityClassDescriptionWithEntity: (EOEntity *)entity +{ + return [[[self alloc] initWithEntity: entity] autorelease]; +} + +- (id)initWithEntity: (EOEntity *)entity +{ + if ((self = [super init])) + { + ASSIGN(_entity, entity); + } + + return self; +} + +- (void) dealloc +{ + //OK + EOFLOGObjectLevelArgs(@"EOEntity", @"Deallocate EOEntityClassDescription %p", + self); + + fflush(stdout); + fflush(stderr); + + DESTROY(_entity); + + [super dealloc]; +} + +- (NSString *) description +{ + return [NSString stringWithFormat: @"<%s %p - Entity: %@>", + object_get_class_name(self), + self, + [self entityName]]; +} + +- (EOEntity *)entity +{ + return _entity; +} + +- (NSString *)entityName +{ + return [_entity name]; +} + +- (NSArray *)attributeKeys +{ + //OK + return [_entity classPropertyAttributeNames]; +} + +- (void)awakeObject: (id)object +fromFetchInEditingContext: (EOEditingContext *)context +{ + //OK + [super awakeObject: object + fromFetchInEditingContext: context]; + //nothing to do +} + +- (void)awakeObject: (id)object +fromInsertionInEditingContext: (EOEditingContext *)anEditingContext +{ + //near OK + [super awakeObject: object + fromInsertionInEditingContext: anEditingContext]; + { + NSArray *relationships = [_entity relationships]; + NSArray *classProperties = [_entity classProperties];//TODO use it ! + int i, count = [relationships count]; + + for (i = 0; i < count; i++) + { + EORelationship *relationship = [relationships objectAtIndex: i]; + BOOL isToMany = [relationship isToMany]; + + if (isToMany) + { + //Put an empty muable array [Ref: Assigns empty arrays to to-many relationship properties of newly inserted enterprise objects] + [object takeStoredValue: [EOCheapCopyMutableArray array] + forKey: [relationship name]]; + } + else //?? + { + BOOL propagatesPrimaryKey = [relationship propagatesPrimaryKey]; + + if (propagatesPrimaryKey) + { + int classPropIndex = [classProperties + indexOfObjectIdenticalTo: relationship]; + + if (classPropIndex == NSNotFound) + { + NSEmitTODO(); //TODO + [self notImplemented: _cmd]; //TODO gid + } + else + { + NSString *relationshipName = [relationship name]; + id relationshipValue = [object valueForKey: + relationshipName];//nil + + if (relationshipValue) + { + //Do nothing ?? + NSEmitTODO(); //TODO + [self notImplemented: _cmd];//TODO?? + } + else + { + EOEntity *relationshipDestinationEntity = + [relationship destinationEntity]; + EOClassDescription *classDescription = + [relationshipDestinationEntity + classDescriptionForInstances]; + + relationshipValue = [classDescription + createInstanceWithEditingContext: + anEditingContext + globalID: nil + zone: NULL]; + + [object addObject: relationshipValue + toBothSidesOfRelationshipWithKey: + relationshipName]; + + [anEditingContext insertObject: relationshipValue]; + /* + //Mirko code + EOEntity *entityTo; + + objectTo = [object storedValueForKey:[relationship name]]; + entityTo = [relationship destinationEntity]; + + if ([relationship isMandatory] == YES && objectTo == nil) + { + EODatabaseOperation *opTo; + EOGlobalID *gidTo; + + objectTo = [[entityTo classDescriptionForInstances] + createInstanceWithEditingContext:context + globalID:nil + zone:NULL]; + + gidTo = [entityTo globalIDForRow:newPK]; + + opTo = [self _dbOperationWithGlobalID:gidTo + object:objectTo + entity:entityTo + operator:EODatabaseInsertOperator]; + } + + if (objectTo && [entityTo + isPrimaryKeyValidInObject:objectTo] == NO) + { + pk = [[[entityTo primaryKeyAttributeNames] mutableCopy] + autorelease]; + [pk removeObjectsInArray:[entityTo classPropertyNames]]; + + pkObj = [[newPK mutableCopy] autorelease]; + [pkObj removeObjectsForKeys:pk]; + + [objectTo takeStoredValuesFromDictionary:pkObj]; + } + */ + } + } + } + } + } + } +} + +- (EOClassDescription *)classDescriptionForDestinationKey: (NSString *)detailKey +{ + EOClassDescription *cd = nil; + EOEntity *destEntity = nil; + EORelationship *rel = nil; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOEntity", @"detailKey=%@", detailKey); + EOFLOGObjectLevelArgs(@"EOEntity", @"_entity name=%@", [_entity name]); + + rel = [_entity relationshipNamed: detailKey]; + EOFLOGObjectLevelArgs(@"EOEntity", @"rel=%@", rel); + + destEntity = [rel destinationEntity]; + EOFLOGObjectLevelArgs(@"EOEntity", @"destEntity name=%@", [destEntity name]); + + cd = [destEntity classDescriptionForInstances]; + EOFLOGObjectLevelArgs(@"EOEntity", @"cd=%@", cd); + + EOFLOGObjectFnStop(); + + return cd; +} + +- (id)createInstanceWithEditingContext: (EOEditingContext *)editingContext + globalID: (EOGlobalID *)globalID + zone: (NSZone *)zone +{ + id obj = nil; + Class objectClass; + + EOFLOGObjectFnStart(); + + NSAssert1(_entity, @"No _entity in %@", self); + + objectClass = [_entity classForObjectWithGlobalID: (EOKeyGlobalID*)globalID]; + EOFLOGObjectLevelArgs(@"EOEntity", @"objectClass=%p", objectClass); + + NSAssert2(objectClass, @"No objectClass for globalID=%@. EntityName=%@", + globalID, [_entity name]); + + if (objectClass) + { + EOFLOGObjectLevelArgs(@"EOEntity", @"objectClass=%@", objectClass); + + obj = [[objectClass allocWithZone:zone] + initWithEditingContext: editingContext + classDescription: self + globalID: globalID]; + } + + [obj autorelease]; + + EOFLOGObjectFnStop(); + + return obj; +} + +- (NSFormatter *)defaultFormatterForKey: (NSString *)key +{ + [self notImplemented: _cmd]; + return nil; +} + +- (NSFormatter *)defaultFormatterForKeyPath: (NSString *)keyPath +{ + [self notImplemented: _cmd]; + return nil; //TODO +} + +- (EODeleteRule)deleteRuleForRelationshipKey: (NSString *)relationshipKey +{ + EORelationship *rel = nil; + EODeleteRule deleteRule = 0; + + EOFLOGObjectFnStart(); + + rel = [_entity relationshipNamed: relationshipKey]; + EOFLOGObjectLevelArgs(@"EOEntity", @"relationship %p=%@", rel, rel); + + deleteRule = [rel deleteRule]; + EOFLOGObjectLevelArgs(@"EOEntity", @"deleteRule=%d", (int)deleteRule); + + EOFLOGObjectFnStop(); + + return deleteRule; +} + +- (NSString *)inverseForRelationshipKey: (NSString *)relationshipKey +{ + //Near OK + NSString *inverseName = nil; + EORelationship *relationship = [_entity relationshipNamed: relationshipKey]; + NSArray *classProperties = [_entity classProperties]; + EOEntity *parentEntity = [_entity parentEntity]; + //TODO what if parentEntity + EORelationship *inverseRelationship = [relationship inverseRelationship]; + + if (inverseRelationship) + { + /* EOEntity *inverseRelationshipEntity = + [inverseRelationship entity]; + NSArray *inverseRelationshipClassProperties = + [inverseRelationshipEntity classProperties];*/ + + inverseName = [inverseRelationship name]; + } + + return inverseName; +} + +- (BOOL)ownsDestinationObjectsForRelationshipKey: (NSString*)relationshipKey +{ + //OK + return [[_entity relationshipNamed: relationshipKey] ownsDestination]; +} + +- (NSArray *)toManyRelationshipKeys +{ + //OK + return [_entity classPropertyToManyRelationshipNames]; +} + +- (NSArray *)toOneRelationshipKeys +{ + //OK + return [_entity classPropertyToOneRelationshipNames]; +} + +- (EORelationship *)relationshipNamed: (NSString *)relationshipName +{ + //OK + return [_entity relationshipNamed:relationshipName]; +} + +- (EORelationship *)anyRelationshipNamed: (NSString *)relationshipName +{ + return [_entity anyRelationshipNamed:relationshipName]; +} + +- (NSException *) validateObjectForDelete: (id)object +{ + return [_entity validateObjectForDelete:object]; +} + +- (NSException *)validateObjectForSave: (id)object +{ + return nil; //Does Nothing ? works is done in record +} + +- (NSException *)validateValue: (id *)valueP + forKey: (NSString *)key +{ + NSException *exception = nil; + EOAttribute *attr; + EORelationship *relationship; + + NSAssert(valueP, @"No value pointer"); + + attr = [_entity attributeNamed: key]; + + if (attr) + { + exception = [attr validateValue: valueP]; + } + else + { + relationship = [_entity relationshipNamed: key]; + + if (relationship) + { + exception = [relationship validateValue: valueP]; + } + else + { + NSEmitTODO(); //TODO + } + } + + return exception; +} + +@end diff --git a/EOAccess/EOEntityPriv.h b/EOAccess/EOEntityPriv.h new file mode 100644 index 0000000..fc72526 --- /dev/null +++ b/EOAccess/EOEntityPriv.h @@ -0,0 +1,68 @@ +/* + EOEntityPriv.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: July 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOEntityPriv_h__ +#define __EOEntityPriv_h__ + + +@interface EOEntity (EOEntityPrivate) + +- (void)setCreateMutableObjects: (BOOL)flag; +- (BOOL)createsMutableObjects; + +- (void)setModel: (EOModel *)model; +- (void)setParentEntity: (EOEntity *)parent; + +@end + +@interface EOEntity (EOEntityRelationshipPrivate) +- (EORelationship*) _inverseRelationshipPathForPath: (NSString*)path; +- (id) _keyMapForRelationshipPath: (NSString*)path; +- (id) _keyMapForIdenticalKeyRelationshipPath: (id)param0; +- (id) _mapAttribute: (id)param0 +toDestinationAttributeInLastComponentOfRelationshipPath: (NSString*)path; +- (BOOL) _relationshipPathIsToMany: (id)param0; +- (BOOL) _relationshipPathHasIdenticalKeys: (id)param0; +@end + +@class EOExpressionArray; + +@interface EOEntity (EOEntitySQLExpression) +- (id) valueForSQLExpression: (id)param0; ++ (id) valueForSQLExpression: (id)param0; +@end + +@interface EOEntity (EOEntityPrivateXX) +- (EOExpressionArray *) _parseDescription: (NSString *)description + isFormat: (BOOL)isFormat + arguments: (char*)param2; +- (EOExpressionArray*) _parseRelationshipPath: (NSString*)path; +- (id) _parsePropertyName: (id)param0; +//- (id) _newStringWithBuffer: (unsigned short*)param0 +// length: (unsigned int*)param1; +@end + +#endif diff --git a/EOAccess/EOExpressionArray.h b/EOAccess/EOExpressionArray.h new file mode 100644 index 0000000..8c43d27 --- /dev/null +++ b/EOAccess/EOExpressionArray.h @@ -0,0 +1,107 @@ +/* + EOExpressionArray.h + + Copyright (C) 1996 Free Software Foundation, Inc. + + Author: Ovidiu Predescu + Date: September 1996 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOExpressionArray_h__ +#define __EOExpressionArray_h__ + +#import +#import + +@class EOAttribute; +@class EOEntity; +@class EOExpressionArray; + +@protocol EOExpressionContext + +- (NSString *)expressionValueForAttribute: (EOAttribute *)anAttribute; +- (NSString *)expressionValueForAttributePath: (NSArray *)path; + +@end + + +@interface EOExpressionArray : GCMutableArray +{ + NSString *_prefix; + NSString *_infix; + NSString *_suffix; +// NSString *_definition; it's rebuilt + EOAttribute *_realAttribute; + + struct + { + unsigned int isFlattened:1; //TODO Why ? + } _flags; +} + ++ (EOExpressionArray*)expressionArray; ++ (EOExpressionArray*)expressionArrayWithPrefix: (NSString *)prefix + infix: (NSString *)infix + suffix: (NSString *)suffix; + +/* Initializing instances */ +- initWithPrefix: (NSString *)prefix + infix: (NSString *)infix + suffix: (NSString *)suffix; + +- (NSString *)prefix; +- (NSString *)infix; +- (NSString *)suffix; + +- (NSString *)definition; +- (BOOL)isFlattened; +- (EOAttribute *)realAttribute; + +/* Accessing the components */ +- (void)setPrefix: (NSString*)prefix; +- (void)setInfix: (NSString*)infix; +- (void)setSuffix: (NSString*)suffix; + +/* Checking contents */ +- (BOOL)referencesObject: (id)anObject; + +- (NSString *)expressionValueForContext: (id)ctx; + ++ (EOExpressionArray *)parseExpression: (NSString *)expression + entity: (EOEntity *)entity + replacePropertyReferences: (BOOL)flag; + +- (NSString*)valueForSQLExpression: (EOSQLExpression *)sqlExpression; + +@end /* EOExpressionArray */ + + +@interface NSObject (EOExpression) +- (NSString*)expressionValueForContext: (id)context; +@end + + +@interface NSString (EOAttributeTypeCheck) + +- (BOOL)isNameOfARelationshipPath; + +@end + +#endif /* __EOExpressionArray_h__ */ diff --git a/EOAccess/EOExpressionArray.m b/EOAccess/EOExpressionArray.m new file mode 100644 index 0000000..c029b05 --- /dev/null +++ b/EOAccess/EOExpressionArray.m @@ -0,0 +1,400 @@ +/** + EOExpressionArray.m EOExpressionArray + + Copyright (C) 1996-2002 Free Software Foundation, Inc. + + Author: Ovidiu Predescu + Date: September 1996 + + Author: Mirko Viviani + Date: February 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import +#import +#import +#import + +#import +#import +#import +#import + +#import +#import +#import +#import + +@implementation EOExpressionArray + ++ (void)initialize +{ + static BOOL initialized = NO; + + if (!initialized) + { + initialized = YES; + class_add_behavior(self, [GCArray class]); + } +} + ++ (EOExpressionArray*)expressionArray +{ + return [[self new] autorelease]; +} + +- (id) init +{ + EOFLOGObjectFnStart(); + + self = [super init]; + + EOFLOGObjectFnStop(); + + return self; +} + ++ (EOExpressionArray*)expressionArrayWithPrefix: (NSString *)prefix + infix: (NSString *)infix + suffix: (NSString *)suffix +{ + return [[[self alloc]initWithPrefix: prefix + infix: infix + suffix: suffix] autorelease]; +} + +- (id)initWithPrefix: (NSString *)prefix + infix: (NSString *)infix + suffix: (NSString *)suffix +{ + EOFLOGObjectFnStart(); + + if ((self = [self init])) + { + ASSIGN(_prefix, prefix); + ASSIGN(_infix, infix); + ASSIGN(_suffix, suffix); + } + + EOFLOGObjectFnStop(); + + return self; +} + +- (void)dealloc +{ + DESTROY(_realAttribute); //TODO mettere nei metodi GC +// DESTROY(_definition); + [_prefix release]; + [_infix release]; + [_suffix release]; + + [super dealloc]; +} + +- (BOOL)referencesObject: (id)anObject +{ + return [self indexOfObject: anObject] != NSNotFound; +} + +- (NSString *)expressionValueForContext: (id)ctx +{ + if (ctx && [self count] + && [[self objectAtIndex: 0] isKindOfClass: [EORelationship class]]) + return [ctx expressionValueForAttributePath: self]; + else + { + int i, count = [self count]; + id result = [[NSMutableString new] autorelease]; + SEL sel = @selector(appendString:); + IMP imp = [result methodForSelector: sel]; + + if (_prefix) + [result appendString:_prefix]; + + if (count) + { + (*imp)(result, sel, [[self objectAtIndex: 0] + expressionValueForContext: ctx]); + + for (i = 1 ; i < count; i++) + { + if (_infix) + (*imp)(result, sel, _infix); + (*imp)(result, sel, [[self objectAtIndex: i] + expressionValueForContext: ctx]); + } + } + + if(_suffix) + [result appendString: _suffix]; + + return result; + } +} + +- (void)setPrefix: (NSString *)prefix +{ + ASSIGN(_prefix, prefix); +} + +- (void)setInfix: (NSString *)infix +{ + ASSIGN(_infix, infix); +} + +- (void)setSuffix: (NSString *)suffix +{ + ASSIGN(_suffix, suffix); +} + +- (NSString *)prefix +{ + return _prefix; +} + +- (NSString *)infix +{ + return _infix; +} + +- (NSString *)suffix +{ + return _suffix; +} + +- (NSString *)definition +{ +// return _definition; + return [self valueForSQLExpression: nil]; +} + +- (BOOL)isFlattened +{ +// return _flags.isFlattened; + return ([self count] > 1); +} + +- (EOAttribute *)realAttribute +{ + return _realAttribute; +} + +/* ++ (EOExpressionArray *)parseExpression:(NSString *)expression + entity:(EOEntity *)entity + replacePropertyReferences:(BOOL)replacePropertyReferences +{ + EOExpressionArray *array = nil; + const char *s = NULL; + const char *start=NULL; + id objectToken=nil; + EOFLOGObjectFnStart(); + NSDebugMLLog(@"gsdb",@"expression=%@",expression); + NSDebugMLLog(@"gsdb",@"entity=%@",entity); + + array = [[EOExpressionArray new] autorelease]; + s = [expression cString]; + +// ASSIGN(array->_definition, expression); + array->_flags.isFlattened = NO; + + if([expression isNameOfARelationshipPath]) + { + NSArray *defArray; + NSString *realAttributeName; + int count, i; + + array->_flags.isFlattened = YES; + defArray = [expression componentsSeparatedByString:@"."]; + count = [defArray count]; + + for(i = 0; i < count - 1; i++) + { + id relationshipName = [defArray objectAtIndex:i]; + id relationship=nil; + + relationship = [entity relationshipNamed:relationshipName]; + + if(!relationship) + [NSException raise:NSInvalidArgumentException + format:@"%@ -- %@ 0x%x: '%@' for entity '%@' is an invalid property", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + relationshipName, + entity]; + + // if([relationship isToMany]) + // [NSException raise:NSInvalidArgumentException format:@"%@ -- %@ 0x%x: '%@' for entity '%@' must be a to one relationship", + //NSStringFromSelector(_cmd), + //NSStringFromClass([self class]), + //self, + //relationshipName, + //entity]; + + [array addObject:relationship]; + entity = [relationship destinationEntity]; + } + realAttributeName = [defArray lastObject]; + ASSIGN(array->_realAttribute, [entity attributeNamed:realAttributeName]); + + if(!array->_realAttribute) + ASSIGN(array->_realAttribute, [entity relationshipNamed:realAttributeName]); + + if(!array->_realAttribute) + [NSException raise:NSInvalidArgumentException + format:@"%@ -- %@ 0x%x: '%@' for entity '%@' is an invalid property", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + realAttributeName, + entity]; + + [array addObject:array->_realAttribute]; + } + else + { + //IN eoentity persedescr + } + NSDebugMLLog(@"gsdb",@"_prefix=%@",array->_prefix); + NSDebugMLLog(@"gsdb",@"_infix=%@",array->_infix); + NSDebugMLLog(@"gsdb",@"_suffix=%@",array->_suffix); +// NSDebugMLLog(@"gsdb",@"_definition=%@",array->_definition); + NSDebugMLLog(@"gsdb",@"_realAttribute=%@",array->_realAttribute); + + EOFLOGObjectFnStop(); + return array; +} +*/ + +- (BOOL)_isPropertyPath +{ +/* + int i=0; + int count=0; + + count=[self count]; +objectAtIndex:i +if it's a string return NO +*/ +//TODO + + return NO; +} + +- (NSString *)valueForSQLExpression: (EOSQLExpression*)sqlExpression +{ + //TODO verify + NSMutableString *value = [NSMutableString string]; + int i, count; + + NS_DURING //Just for debugging + { + count = [self count]; + + for(i = 0; i < count; i++) + { + id obj = [self objectAtIndex: i]; + NSString *relValue; + + relValue = [obj valueForSQLExpression: sqlExpression]; + + if (i > 0) + [value appendString: @"."]; + + [value appendString: relValue]; + } + } + NS_HANDLER + { + NSLog(@"exception in EOExpressionArray valueForSQLExpression: self=%p class=%@ i=%d", self, [self class], i); + NSLog(@"exception in EOExpressionArray valueForSQLExpression: self=%@ class=%@ i=%d", self, [self class], i); + NSLog(@"exception=%@", localException); + + [localException raise]; + } + NS_ENDHANDLER; + + return value; +} +@end /* EOExpressionArray */ + + +@implementation NSObject (EOExpression) + +- (NSString*)expressionValueForContext: (id)ctx +{ + if ([self respondsToSelector: @selector(stringValue)]) + return [(id)self stringValue]; + else + return [self description]; +} + +@end + + +@implementation NSString (EOExpression) + +/* Avoid returning the description in case of NSString because if the string + contains whitespaces it will be quoted. Particular adaptors have to override + -formatValue:forAttribute: and they have to quote with the specific + database character the returned string. */ +- (NSString*)expressionValueForContext: (id)ctx +{ + return self; +} + +@end + +@implementation NSString (EOAttributeTypeCheck) + +- (BOOL)isNameOfARelationshipPath +{ + const char *s = [self cString]; + BOOL result = NO; + + if (isalnum(*s) || *s == '@' || *s == '_' || *s == '#') + { + for (++s; *s; s++) + { + if (!isalnum(*s) && *s != '@' && *s != '_' && *s != '#' && *s != '$' + && *s != '.') + return NO; + + if (*s == '.') + result = YES; + } + } + + return result; +} + +@end diff --git a/EOAccess/EOJoin.h b/EOAccess/EOJoin.h new file mode 100644 index 0000000..71bb77a --- /dev/null +++ b/EOAccess/EOJoin.h @@ -0,0 +1,70 @@ +/* + EOJoin.h + + Copyright (C) 1996 Free Software Foundation, Inc. + + Author: Ovidiu Predescu + Date: August 1996 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOJoin_h__ +#define __EOJoin_h__ + +#import +#import + + +@class EOEntity; +@class EOAttribute; + + +@interface EOJoin : GCObject +{ + /* Garbage collectable objects */ + EOAttribute *_sourceAttribute; + EOAttribute *_destinationAttribute; +} + ++ (EOJoin *)joinWithSourceAttribute: (EOAttribute *)source + destinationAttribute: (EOAttribute *)destination; + +- initWithSourceAttribute: (EOAttribute *)source + destinationAttribute: (EOAttribute *)destination; + +- (NSString *)description; + +- (EOAttribute *)sourceAttribute; +- (EOAttribute *)destinationAttribute; + +- (BOOL)isReciprocalToJoin: (EOJoin *)otherJoin; + +@end + + +@interface EOJoin (EOJoinPrivate) + +//+ (EOJoin*)joinFromPropertyList:(id)propertyList; +//- (void)replaceStringsWithObjectsInRelationship:(EORelationship*)entity; +//- (id)propertyList; + +@end /* EOJoin (EOJoinPrivate) */ + + +#endif /* __EOJoin_h__ */ diff --git a/EOAccess/EOJoin.m b/EOAccess/EOJoin.m new file mode 100644 index 0000000..66660fa --- /dev/null +++ b/EOAccess/EOJoin.m @@ -0,0 +1,202 @@ +/** + EOJoin.m EOJoin Class + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import + +#import +#import + +#import +#import +#import +#import +#import +#import + + +@implementation EOJoin + ++ (EOJoin *) joinWithSourceAttribute: (EOAttribute *)source + destinationAttribute: (EOAttribute *)destination +{ + return [[[self alloc] initWithSourceAttribute: source + destinationAttribute: destination] autorelease]; +} + +- (id) initWithSourceAttribute: (EOAttribute *)source + destinationAttribute: (EOAttribute *)destination +{ + if ((self = [super init])) + { + if (!source || !destination) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: source and destination attributes can't be nil", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + + ASSIGN(_sourceAttribute, source); + ASSIGN(_destinationAttribute, destination); + } + + return self; +} + +- (void)gcDecrementRefCountOfContainedObjects +{ + EOFLOGObjectFnStart(); + + NSDebugMLLog(@"gsdb", @"sourceAttribute gcDecrementRefCount"); + + [_sourceAttribute gcDecrementRefCount]; + NSDebugMLLog(@"gsdb", @"destinationAttribute gcDecrementRefCount"); + + [_destinationAttribute gcDecrementRefCount]; + + EOFLOGObjectFnStop(); +} + +- (BOOL)gcIncrementRefCountOfContainedObjects +{ + if (![super gcIncrementRefCountOfContainedObjects]) + return NO; + + [_sourceAttribute gcIncrementRefCount]; + [_destinationAttribute gcIncrementRefCount]; + + [_sourceAttribute gcIncrementRefCountOfContainedObjects]; + [_destinationAttribute gcIncrementRefCountOfContainedObjects]; + + return YES; +} + +- (unsigned)hash +{ + return [_sourceAttribute hash]; +} + +- (NSString *)description +{ + NSString *dscr = nil; +/*NSString *joinOperatorDescr = nil; + NSString *joinSemanticDescr = nil; + + switch(joinOperator) + { + case EOJoinEqualTo: + joinOperatorDescr=@"EOJoinEqualTo"; + break; + case EOJoinNotEqualTo: + joinOperatorDescr=@"EOJoinNotEqualTo"; + break; + case EOJoinGreaterThan: + joinOperatorDescr=@"EOJoinGreaterThan"; + break; + case EOJoinGreaterThanOrEqualTo: + joinOperatorDescr=@"EOJoinGreaterThanOrEqualTo"; + break; + case EOJoinLessThan: + joinOperatorDescr=@"EOJoinLessThan"; + break; + case EOJoinLessThanOrEqualTo: + joinOperatorDescr=@"EOJoinLessThanOrEqualTo"; + break; + }; + switch(joinSemantic) + { + case EOInnerJoin: + joinSemanticDescr=@"EOInnerJoin"; + break; + case EOFullOuterJoin: + joinSemanticDescr=@"EOFullOuterJoin"; + break; + case EOLeftOuterJoin: + joinSemanticDescr=@"EOLeftOuterJoin"; + break; + case EORightOuterJoin: + joinSemanticDescr=@"EORightOuterJoin"; + break; + }; +*/ + + dscr = [NSString stringWithFormat: @"<%s %p -", + object_get_class_name(self), + (void*)self]; + dscr = [dscr stringByAppendingFormat: @" sourceAttribute=%@", + [_sourceAttribute name]]; + dscr = [dscr stringByAppendingFormat: @" destinationAttribute=%@", + [_destinationAttribute name]]; + +/* dscr=[dscr stringByAppendingFormat:@" relationship name=%@", + [relationship name]]; + dscr=[dscr stringByAppendingFormat:@" joinOperator=%@ joinSemantic=%@>", + joinOperatorDescr, + joinSemanticDescr];*/ + + return dscr; +} + +- (EOAttribute *)destinationAttribute +{ + return _destinationAttribute; +} + +- (EOAttribute *)sourceAttribute +{ + return _sourceAttribute; +} + +- (BOOL)isReciprocalToJoin: (EOJoin *)otherJoin +{ + //OK + NSDebugMLLog(@"gsdb", @"_sourceAttribute name=%@", + [_sourceAttribute name]); + NSDebugMLLog(@"gsdb", @"[[otherJoin destinationAttribute] name]=%@", + [[otherJoin destinationAttribute] name]); + NSDebugMLLog(@"gsdb", @"_destinationAttribute name=%@", + [_destinationAttribute name]); + NSDebugMLLog(@"gsdb", @"[[otherJoin sourceAttribute] name]=%@", + [[otherJoin sourceAttribute] name]); + + if ([[_sourceAttribute name] + isEqual: [[otherJoin destinationAttribute] name]] + && [[_destinationAttribute name] + isEqual: [[otherJoin sourceAttribute] name]]) + return YES; + else + return NO; +} + +@end diff --git a/EOAccess/EOModel.h b/EOAccess/EOModel.h new file mode 100644 index 0000000..24eec44 --- /dev/null +++ b/EOAccess/EOModel.h @@ -0,0 +1,191 @@ +/* + EOModel.h + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOModel_h__ +#define __EOModel_h__ + +#import +#import +#import +#import + +#import + +@class EOEntity; +@class EOModelGroup; +@class EOStoredProcedure; + + +@interface EOModel : GCObject +{ + NSString *_name; + NSString *_path; + NSString *_adaptorName; + NSString *_adaptorClassName; + float _version; + NSDictionary *_connectionDictionary; + NSDictionary *_userInfo; + NSDictionary * _internalInfo; + NSString *_docComment; + void *_entitiesByClass; + + /* Garbage collectable objects */ + EOModelGroup *_group; + + GCArray *_entities; + GCMutableDictionary *_entitiesByName; + GCMutableArray *_storedProcedures; + GCMutableDictionary *_subEntitiesCache; + //GCMutableDictionary *_prototypesByName; + struct + { + BOOL createsMutableObjects:1; + BOOL errors:1; + } _flags; +} + ++ (EOModel *)model; + +/** Getting the filename **/ +- (NSString*)path; + +/** Getting the name **/ +- (NSString *)name; +- (NSString *)adaptorName; +- (NSString *)adaptorClassName; + +- (float)version; ++ (float)version; + +/** Using entities **/ +- (EOEntity *)entityNamed: (NSString*)name; +- (NSArray *)entities; +- (NSArray *)entityNames; + +- (NSArray *)storedProcedureNames; +- (EOStoredProcedure *)storedProcedureNamed: (NSString *)name; +- (NSArray *)storedProcedures; + +/** Getting an object's entity **/ +- (EOEntity *)entityForObject: object; + +/** Accessing the connection dictionary **/ +- (NSDictionary *)connectionDictionary; + +/** Accessing the user dictionary **/ +- (NSDictionary *)userInfo; + +/** Accessing documentation comments **/ +- (NSString*)docComment; + +- (EOModelGroup *)modelGroup; + +@end + +@interface EOModel (EOModelFileAccess) + ++ (EOModel *)modelWithContentsOfFile: (NSString *)path; +- initWithContentsOfFile: (NSString *)path; +- (void)writeToFile: (NSString *)path; + +@end + +@interface EOModel (EOModelPropertyList) + +- (id) initWithTableOfContentsPropertyList: (NSDictionary *)tableOfContents + path: (NSString *)path; +- (void)encodeTableOfContentsInfoPropertyList: (NSMutableDictionary *)propertyList; + +- (void)encodeIntoPropertyList: (NSMutableDictionary *)propertyList; +- (void)awakeWithPropertyList: (NSDictionary *)propertyList; +- (id)initWithPropertyList: (NSDictionary *)propertyList + owner: (id)owner; +@end + +@interface EOModel (EOModelHidden) + +- (void)_resetPrototypeCache; +- (BOOL)isPrototypesEntity: (id)param0; +- (void)_classDescriptionNeeded: (id)param0; +- (id)_instantiatedEntities; +- (void)_setPath: (NSString *)path; +- (id)_entityForClass: (Class)param0; +- (id)_childrenForEntityNamed: (id)param0; +- (void)_registerChild: (id)param0 + forParent: (id)param1; +- (void)_setInheritanceLinks: (id)param0; +- (void)_removeEntity: (id)param0; +- (id)_addEntityWithPropertyList: (NSDictionary *)propertyList; +- (void)_addFakeEntityWithPropertyList: (NSDictionary *)propertyList; +- (id)_addEntity: (EOEntity *)entity; +- (void)_setEntity: (id)entity + forEntityName: (NSString *)entityName + className: (NSString *)className; +@end + +@interface EOModel (EOModelEditing) + +/* Accessing the adaptor bundle */ +- (void)setName: (NSString *)name; +- (void)setAdaptorName: (NSString *)adaptorName; + +- (void)setConnectionDictionary: (NSDictionary *)connectionDictionary; +- (void)setUserInfo: (NSDictionary *)dictionary; + +- (void)addEntity: (EOEntity *)entity; +- (void)removeEntity: (EOEntity *)entity; +- (void)removeEntityAndReferences: (EOEntity *)entity; + +- (void)addStoredProcedure: (EOStoredProcedure *)storedProcedure; +- (void)removeStoredProcedure: (EOStoredProcedure *)storedProcedure; + +- (void)setModelGroup: (EOModelGroup *)group; +- (void)loadAllModelObjects; + +/* Checking references */ +- (NSArray *)referencesToProperty: property; +- (NSArray *)externalModelsReferenced; + +@end + +@interface EOModel (EOModelBeautifier) + +- (void)beautifyNames; + +@end + +extern NSString *EOEntityLoadedNotification; + +@interface EOModel (EOModelPrivate) + +- (void)setCreateMutableObjects: (BOOL)flag; +- (BOOL)createsMutableObjects; +- (EOEntity *)_verifyBuiltEntityObject: (id)entity + named: (NSString *)name; + +@end /* EOModel (EOModelPrivate) */ + +#endif /* __EOModel_h__ */ diff --git a/EOAccess/EOModel.m b/EOAccess/EOModel.m new file mode 100644 index 0000000..9be300d --- /dev/null +++ b/EOAccess/EOModel.m @@ -0,0 +1,1608 @@ +/** + EOModel.m EOModel Class + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Manuel Guesdon + Date: February 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import + +#import +#import +#import +#import + +#import +#import + +#import +#import +#import +#import +#import +#import + +#import +#import +#import +#import +#import +#import +#import + +#include + + +NSString *EOEntityLoadedNotification = @"EOEntityLoadedNotification"; + + +@implementation EOModel + ++ (EOModel *)model +{ + return [[[self alloc] init] autorelease]; +} + ++ (NSString *)findPathForModelNamed: (NSString *)modelName +{ + NSString *modelPath = nil; + NSString *tmpModelName = nil; + NSString *tmpPath = nil; + NSBundle *bundle = nil; + NSString *paths[] = { @"~/Library/Models", + @"/LocalLibrary/Models", + @"/NextLibrary/Models", + nil }; + + tmpModelName = [modelName lastPathComponent]; + NSDebugMLLog(@"gsdb", @"modelName=%@ tmpModelName=%@", + modelName, tmpModelName); + + tmpPath = [[modelName stringByStandardizingPath] + stringByDeletingLastPathComponent]; + NSDebugMLLog(@"gsdb", @"modelName=%@ tmpPath=%@", modelName, tmpPath); + + bundle = [NSBundle mainBundle]; + modelPath = [bundle pathForResource: modelName + ofType: @"eomodel"]; + + NSDebugMLLog(@"gsdb", @"modelName=%@ modelPath=%@", modelName, modelPath); + + if (!modelPath) + { + modelPath = [bundle pathForResource: modelName + ofType: @"eomodeld"]; + + NSDebugMLLog(@"gsdb", @"modelName=%@ modelPath=%@", + modelName, modelPath); + + if (!modelPath) + { + if ([tmpPath length] == 0) + { + tmpPath = @"./"; + tmpPath = [tmpPath stringByStandardizingPath]; + } + + if ([[tmpModelName pathExtension] length] != 0) + tmpModelName = [tmpModelName stringByDeletingPathExtension]; + + NSDebugMLLog(@"gsdb", @"modelName=%@ tmpPath=%@ tmpModelName=%@", + modelName, tmpPath, tmpModelName); + + bundle = [NSBundle bundleWithPath: tmpPath]; + + modelPath = [bundle pathForResource: tmpModelName + ofType: @"eomodel"]; + + NSDebugMLLog(@"gsdb", @"modelName=%@ modelPath=%@", + modelName, modelPath); + + if (!modelPath) + { + modelPath = [bundle pathForResource: tmpModelName + ofType: @"eomodeld"]; + NSDebugMLLog(@"gsdb", @"modelName=%@ modelPath=%@", + modelName, modelPath); + + if (!modelPath) + { + int i; + + for(i = 0; !modelPath && paths[i]; i++) + { + NSDebugMLLog(@"gsdb", @"Trying path:%@", paths[i]); + + bundle = [NSBundle bundleWithPath: paths[i]]; + + modelPath = [bundle pathForResource: modelName + ofType: @"eomodel"]; + + NSDebugMLLog(@"gsdb", @"modelName=%@ modelPath=%@", + modelName, modelPath); + + if (!modelPath) + { + modelPath = [bundle pathForResource: modelName + ofType: @"eomodeld"]; + + NSDebugMLLog(@"gsdb", @"modelName=%@ modelPath=%@", + modelName, modelPath); + } + } + } + } + } + } + + return modelPath; +} + +- (id) init +{ + EOFLOGObjectFnStart(); + + if ((self = [super init])) + { + // Turbocat + _flags.createsMutableObjects = YES; + + _entitiesByName = [GCMutableDictionary new]; + _entitiesByClass = NSCreateMapTableWithZone(NSObjectMapKeyCallBacks, + NSObjectMapValueCallBacks, + 8, + [self zone]); + + [[NSNotificationCenter defaultCenter] + addObserver: self + selector: @selector(_classDescriptionNeeded:) + name: EOClassDescriptionNeededNotification + object: nil]; + + //No ? + [[NSNotificationCenter defaultCenter] + addObserver: self + selector: @selector(_classDescriptionNeeded:) + name: EOClassDescriptionNeededForClassNotification + object: nil]; + + [[NSNotificationCenter defaultCenter] + addObserver: self + selector: @selector(_classDescriptionNeeded:) + name: EOClassDescriptionNeededForEntityNameNotification + object: nil]; + + [EOClassDescription invalidateClassDescriptionCache]; + } + + EOFLOGObjectFnStop(); + + return self; +} + +- (void)dealloc +{ + [NSNotificationCenter removeObserver: self]; + + if (_entitiesByClass) + { + NSFreeMapTable(_entitiesByClass); + _entitiesByClass = NULL; + } + + DESTROY(_name); + DESTROY(_path); + DESTROY(_adaptorName); + DESTROY(_connectionDictionary); + DESTROY(_userInfo); + DESTROY(_internalInfo); + DESTROY(_docComment); + + [super dealloc]; +} + +- (void)gcDecrementRefCountOfContainedObjects +{ + EOFLOGObjectFnStart(); + + [(id)_group gcDecrementRefCount]; + NSDebugMLLog(@"gsdb", @"entities gcDecrementRefCount"); + + [(id)_entities gcDecrementRefCount]; + NSDebugMLLog(@"gsdb", @"entitiesByName gcDecrementRefCount"); + + [(id)_entitiesByName gcDecrementRefCount]; + NSDebugMLLog(@"gsdb", @"storedProcedures gcDecrementRefCount"); + + [(id)_storedProcedures gcDecrementRefCount]; + NSDebugMLLog(@"gsdb", @"subEntitiesCache gcDecrementRefCount"); + + [(id)_subEntitiesCache gcDecrementRefCount]; + + EOFLOGObjectFnStop(); +} + +- (BOOL)gcIncrementRefCountOfContainedObjects +{ + if (![super gcIncrementRefCountOfContainedObjects]) + return NO; + + [(id)_group gcIncrementRefCount]; + [(id)_entities gcIncrementRefCount]; + [(id)_entitiesByName gcIncrementRefCount]; + [(id)_storedProcedures gcIncrementRefCount]; + [(id)_subEntitiesCache gcIncrementRefCount]; + + [(id)_group gcIncrementRefCountOfContainedObjects]; + [(id)_entities gcIncrementRefCountOfContainedObjects]; + [(id)_entitiesByName gcIncrementRefCountOfContainedObjects]; + [(id)_storedProcedures gcIncrementRefCountOfContainedObjects]; + [(id)_subEntitiesCache gcIncrementRefCountOfContainedObjects]; + + return YES; +} + +/*Mirko: +- (void)_registerClassDescForClass:(NSNotification *)notification +{ + EOEntityClassDescription *classDesc = nil; + Class aClass = [notification object]; + int i; + + if (_entitiesByClass == NULL) + return; + + for (i = 0; ((Class *)_entitiesByClass)[i]; i = i + 2) + { + if(aClass == ((Class *)_entitiesByClass)[i]) + { + classDesc = [EOEntityClassDescription entityClassDescriptionWithEntity: ((EOEntity **)_entitiesByClass)[i+1]]; + + [EOClassDescription registerClassDescription:classDesc + forClass:aClass]; + + return; + } + } +} + +- (void)_registerClassDescForEntityName:(NSNotification *)notification +{ + EOEntityClassDescription *classDesc; + NSString *entityName = [notification object]; + EOEntity *entity; + + entity = [self entityNamed:entityName]; + + if (entity) + { + classDesc = [EOEntityClassDescription entityClassDescriptionWithEntity: entity]; + + [EOClassDescription registerClassDescription: classDesc + forClass: NSClassFromString([entity className])]; + } +} +*/ + +- (NSString *)path +{ + return _path; +} + +- (NSString *)name +{ + return _name; +} + +- (NSString *)adaptorName +{ + return _adaptorName; +} + +- (NSString *)adaptorClassName +{ + return _adaptorClassName; +} + +- (float)version +{ + return _version; +} + +- (EOEntity *)entityNamed:(NSString *)name +{ + EOEntity *entity = nil; + + NSAssert(name,@"No entityt name"); + + entity = [_entitiesByName objectForKey: name]; + entity = [self _verifyBuiltEntityObject: entity + named: name]; + + return entity; +} + +- (NSArray*)entities +{ + //TODO revoir ? + if (!_entities) + { + NSArray *entityNames = [self entityNames]; + + ASSIGN(_entities, + [self resultsOfPerformingSelector: @selector(entityNamed:) + withEachObjectInArray: entityNames]); + } + + return _entities; +} + +- (NSArray *)entityNames +{ + return [_entitiesByName allKeys]; +} + +- (NSArray *)storedProcedureNames +{ + + NSEnumerator *stEnum; + EOStoredProcedure *st; + NSMutableArray *stNames = [NSMutableArray arrayWithCapacity: + [_storedProcedures count]]; + + stEnum = [_storedProcedures objectEnumerator]; + while ((st = [stEnum nextObject])) + [stNames addObject: st]; + + return stNames; +} + +- (EOStoredProcedure *)storedProcedureNamed: (NSString *)name +{ + NSEnumerator *stEnum; + EOStoredProcedure *st; + + stEnum = [_storedProcedures objectEnumerator]; + while ((st = [stEnum nextObject])) + { + if ([[st name] isEqual:name]) + return st; + } + + return nil; +} + +- (NSArray *)storedProcedures +{ + //TODO revoir ? + if (!_storedProcedures) + { + NSArray *storedProcedures = nil; + NSArray *storedProcedureNames = [self storedProcedureNames]; + + NSDebugMLLog(@"gsdb", @"storedProcedureNames=%@", storedProcedureNames); + + storedProcedures = [self resultsOfPerformingSelector: + @selector(storedProcedureNamed:) + withEachObjectInArray: storedProcedureNames]; + + NSDebugMLLog(@"gsdb", @"storedProcedures=%@", storedProcedures); + + ASSIGN(_storedProcedures, [GCArray arrayWithArray:storedProcedures]); +/* [self performSelector:@selector(storedProcedureNamed:) + withEachObjectInArray:storedProcedureNames]; +*/ + } + + return _storedProcedures; +} + +- (EOEntity *)entityForObject: object +{ + EOEntity *entity = nil; + NSString *entityName = nil; + + if ([EOFault isFault: object]) + { + EOFaultHandler *handler = [EOFault handlerForFault: object]; + + if ([handler respondsToSelector: @selector(globalID)] == YES) + entityName = [[(EOAccessFaultHandler *)handler globalID] + entityName]; + } + else + { + // if([object isKindOfClass:[EOGenericRecord class]]) + // return [object entity]; + entityName = [object entityName]; + } + + if (entityName) + entity = [self entityNamed:entityName]; + + return entity; +} + +- (NSDictionary *)connectionDictionary +{ + return _connectionDictionary; +} + +- (NSDictionary *)userInfo +{ + return _userInfo; +} + +- (NSString *)docComment +{ + return _docComment; +} + +- (EOModelGroup *)modelGroup +{ + return _group; +} + ++ (float)version +{ + return 2; +} + +@end + + +@implementation EOModel (EOModelFileAccess) + ++ (EOModel *)modelWithContentsOfFile: (NSString *)path +{ + return [[[self alloc] initWithContentsOfFile: path] autorelease]; +} + +- (id) initWithContentsOfFile: (NSString *)path +{ + NS_DURING + { + NSDictionary *propList = nil; + NSString *completePath = [[self class] findPathForModelNamed: path]; + NSString *indexPath = nil; + + NSDebugMLLog(@"gsdb", @"path=%@", path); + NSDebugMLLog(@"gsdb", @"completePath=%@", completePath); + + if ([[completePath pathExtension] isEqualToString: @"eomodeld"]) + indexPath = [completePath stringByAppendingPathComponent: + @"index.eomodeld"]; + else + indexPath = completePath; + + NSDebugMLLog(@"gsdb", @"path=%@ completePath=%@ indexPath=%@", + path, completePath, indexPath); + + propList = [[NSString stringWithContentsOfFile: indexPath] propertyList]; + NSDebugMLLog(@"gsdb", @"propList=%@", propList); + + if (!propList) + { + NSLog(@"Loading model (path=%@ \n index path=%@) failed", + path, + indexPath); + + //Try loading directly from path + if ([[path pathExtension] isEqualToString: @"eomodeld"]) + indexPath = [path stringByAppendingPathComponent: + @"index.eomodeld"]; + else + indexPath = path; + + NSDebugMLLog(@"gsdb", @"path=%@ completePath=%@ indexPath=%@", + path, completePath, indexPath); + + propList = [[NSString stringWithContentsOfFile: indexPath] propertyList]; + + NSDebugMLLog(@"gsdb", @"propList=%@", propList); + } + + //TODO test it + NSAssert2(propList, @"Loading model (path=%@ \n index path=%@) failed", + path, + indexPath); + + //what to do if it fail ? + if ((self = [self initWithTableOfContentsPropertyList: propList + path: path])) + { + } + else + { + NSEmitTODO(); + return [self notImplemented: _cmd]; //TODO + } + } + NS_HANDLER + { + NSLog(@"exception in EOModel initWithContentsOfFile:"); + NSLog(@"exception=%@", localException); +/* localException=ExceptionByAddingUserInfoObjectFrameInfo(localException, + @"In EOModel initWithContentsOfFile:");*/ + NSLog(@"exception=%@", localException); + [localException raise]; + } + NS_ENDHANDLER; + + return self; +} + +- (void)writeToFile: (NSString *)path +{ + NSMutableDictionary *pList; + NSDictionary *entityPList; + NSEnumerator *entityEnum; + + path = [path stringByStandardizingPath]; + path = [[path stringByDeletingPathExtension] + stringByAppendingPathExtension: @"eomodeld"]; + + pList = [NSMutableDictionary dictionaryWithCapacity: 10]; + + [self encodeIntoPropertyList: pList]; + + mkdir([path cString], S_IRWXU | S_IRWXG | S_IRWXO); + + entityEnum = [[pList objectForKey:@"entities"] objectEnumerator]; + while ((entityPList = [entityEnum nextObject])) + { + NSString *fileName; + NSArray *entityArray; + + fileName = [path stringByAppendingPathComponent: + [NSString stringWithFormat: @"%@.plist", + [entityPList objectForKey: @"name"]]]; + entityArray = [NSArray arrayWithObject: entityPList]; + [entityArray writeToFile: fileName atomically: YES]; + } + + { + NSString *fileName; + + fileName = [path stringByAppendingPathComponent: @"index.eomodeld"]; + + [pList removeAllObjects]; + [self encodeTableOfContentsInfoPropertyList: pList]; + [pList writeToFile:fileName atomically: YES]; + } +} + +@end + +@implementation EOModel (EOModelPropertyList) + +- (id) initWithTableOfContentsPropertyList: (NSDictionary *)tableOfContents + path: (NSString *)path +{ + //OK + NS_DURING + { + if ((self = [self init])) + { + NSString *versionString = nil; + NSArray *entities = nil; + int i, count = 0; + + [self _setPath: path]; + _name = [[EOModel findPathForModelNamed: _path] retain]; + + NSDebugMLLog(@"gsdb", @"tableOfContents=%@", tableOfContents); + NSAssert1(_name, @"No name for model (path=%@)", path); + + [self setName: _name];//?? + versionString = [tableOfContents objectForKey: @"EOModelVersion"]; + + if (versionString) + _version = [versionString floatValue]; + + ASSIGN(_connectionDictionary, + [tableOfContents objectForKey: @"connectionDictionary"]); + ASSIGN(_adaptorName, [tableOfContents objectForKey: @"adaptorName"]); + ASSIGN(_userInfo, [tableOfContents objectForKey: @"userInfo"]); + + if (!_userInfo) + { + ASSIGN(_userInfo, + [tableOfContents objectForKey:@"userDictionary"]); + } + + ASSIGN(_internalInfo, + [tableOfContents objectForKey: @"internalInfo"]); + ASSIGN(_docComment,[tableOfContents objectForKey:@"docComment"]); + + //VERIFY + if (_version >= 2) + { + NSMutableDictionary *markSP = [NSMutableDictionary dictionary]; + NSArray *storedProcedures = [tableOfContents + objectForKey: @"storedProcedures"]; + EOStoredProcedure *sp = nil; + NSEnumerator *enumerator = nil; + + count = [storedProcedures count]; + + for (i = 0; i < count; i++) + { + EOStoredProcedure *st; + NSDictionary *plist; + NSString *fileName; + + fileName = [NSString stringWithFormat: @"%@.storedProcedure", + [[storedProcedures objectAtIndex: i] + objectForKey: @"name"]]; + plist = [[NSString stringWithContentsOfFile: + [_name stringByAppendingPathComponent: + fileName]] + propertyList]; + + [markSP setObject: plist + forKey: [plist objectForKey: @"name"]]; + + st = [EOStoredProcedure storedProcedureWithPropertyList: plist + owner: self]; + [self addStoredProcedure: st]; + } + + enumerator = [_storedProcedures objectEnumerator]; + while ((sp = [enumerator nextObject])) + [sp awakeWithPropertyList: [markSP objectForKey: [sp name]]]; + } + + entities = [tableOfContents objectForKey: @"entities"]; + count = [entities count]; + + for (i = 0; i < count; i++) + { + [self _addFakeEntityWithPropertyList: + [entities objectAtIndex: i]]; + } + } + } + NS_HANDLER + { + NSLog(@"exception in EOModel initWithTableOfContentsPropertyList:path:"); + NSLog(@"exception=%@", localException); +/* localException=ExceptionByAddingUserInfoObjectFrameInfo(localException, + @"In EOModel initWithTableOfContentsPropertyList:path:");*/ + NSLog(@"exception=%@", localException); + [localException raise]; + } + NS_ENDHANDLER; + + return self; +} + +- (void)encodeTableOfContentsInfoPropertyList: (NSMutableDictionary *)propertyList +{ + int i, count; + NSMutableArray *entitiesArray; + + [propertyList setObject: [[NSNumber numberWithFloat: [isa version]] stringValue] + forKey: @"EOModelVersion"]; + + if (_adaptorName) + [propertyList setObject: _adaptorName + forKey: @"adaptorName"]; + + if (_connectionDictionary) + [propertyList setObject: _connectionDictionary + forKey: @"connectionDictionary"]; + + if (_userInfo) + [propertyList setObject: _userInfo + forKey: @"userInfo"]; + + if (_docComment) + [propertyList setObject: _docComment forKey: @"docComment"]; + + count = [_entities count]; + entitiesArray = [NSMutableArray arrayWithCapacity: count]; + [propertyList setObject: entitiesArray forKey: @"entities"]; + + for (i = 0; i < count; i++) + { + NSMutableDictionary *entityPList; + EOEntity *entity; + + entity = [_entities objectAtIndex: i]; + entityPList = [NSMutableDictionary dictionaryWithCapacity: 2]; + + [entityPList setObject: [entity className] forKey: @"className"]; + [entityPList setObject: [entity name] forKey: @"name"]; + + [entitiesArray addObject: entityPList]; + } +} + +- (id) initWithPropertyList: (NSDictionary *)propertyList + owner: (id)owner +{ + NS_DURING + { + if (!propertyList) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: must not be the nil object", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + + if (![propertyList isKindOfClass: [NSDictionary class]]) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: must not be kind of NSDictionary class", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + + if ((self = [self init])) + { + int i, count; + NSArray *propListEntities, *propListSt; + NSMutableDictionary *markEntities = + [NSMutableDictionary dictionaryWithCapacity: 10]; + NSMutableDictionary *markSP = + [NSMutableDictionary dictionaryWithCapacity: 10]; + NSEnumerator *enumerator; + EOEntity *entity; + EOStoredProcedure *sp; + + _version = [[propertyList objectForKey: @"EOModelVersion"] + floatValue]; + _adaptorName = [[propertyList objectForKey: @"adaptorName"] retain]; + _connectionDictionary = [[propertyList objectForKey: + @"connectionDictionary"] + retain]; + _userInfo = [[propertyList objectForKey: @"userInfo"] retain]; + _docComment = [[propertyList objectForKey: @"docComment"] retain]; + + propListEntities = [propertyList objectForKey: @"entities"]; + propListSt = [propertyList objectForKey: @"storedProcedures"]; + + _flags.errors = NO; + [self setCreateMutableObjects: YES]; + + count = [propListEntities count]; + for (i = 0; i < count; i++) + { + EOEntity *entity; + NSDictionary *plist; + + plist = [propListEntities objectAtIndex: i]; + NSDebugMLLog(@"gsdb", @"plist=%@ [%@]", plist, [plist class]); + + if (_version >= 2) + { + NSString *fileName = [NSString stringWithFormat: @"%@.plist", + [plist objectForKey: @"name"]]; + + plist = [[NSString stringWithContentsOfFile: + [_name stringByAppendingPathComponent: + fileName]] + propertyList]; + } + + [markEntities setObject: plist + forKey: [plist objectForKey: @"name"]]; + + entity = [EOEntity entityWithPropertyList: plist + owner: self]; + [self addEntity: entity]; + } + + enumerator = [_entities objectEnumerator]; + while ((entity = [enumerator nextObject])) + { + NS_DURING + { + [entity awakeWithPropertyList: + [markEntities objectForKey: [entity name]]]; + } + NS_HANDLER + { + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: exception in model '%@' during awakeWithPropertyList: of entity '%@': %@", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + [self name], + [entity name], + [localException reason]]; + } + NS_ENDHANDLER; + } + + if (_version >= 2) + { + count = [propListSt count]; + for (i = 0; i < count; i++) + { + EOStoredProcedure *st; + NSDictionary *plist; + NSString *fileName; + + fileName = [NSString stringWithFormat: @"%@.storedProcedure", + [[propListSt objectAtIndex: i] + objectForKey: @"name"]]; + + plist = [[NSString stringWithContentsOfFile: + [_name stringByAppendingPathComponent: + fileName]] + propertyList]; + + [markSP setObject: plist + forKey: [plist objectForKey: @"name"]]; + + st = [EOStoredProcedure storedProcedureWithPropertyList: plist + owner: self]; + [self addStoredProcedure: st]; + } + + enumerator = [_storedProcedures objectEnumerator]; + while ((sp = [enumerator nextObject])) + [sp awakeWithPropertyList: [markSP objectForKey: [sp name]]]; + } + + [self setCreateMutableObjects: NO]; + } + } + NS_HANDLER + { + NSLog(@"exception in EOModel initWithPropertyList:owner:"); + NSLog(@"exception=%@", localException); +/* localException=ExceptionByAddingUserInfoObjectFrameInfo(localException, + @"In EOModel initWithPropertyList:owner:"); +*/ + NSLog(@"exception=%@", localException); + [localException raise]; + } + NS_ENDHANDLER; + + return self; +} + +- (void)awakeWithPropertyList: (NSDictionary *)propertyList +{ +} + +- (void)encodeIntoPropertyList: (NSMutableDictionary *)propertyList +{ + int i, count; + + [propertyList setObject: [[NSNumber numberWithFloat: [isa version]] + stringValue] + forKey: @"EOModelVersion"]; + + if(_name) + [propertyList setObject: _name forKey: @"name"]; + if(_adaptorName) + [propertyList setObject: _adaptorName forKey: @"adaptorName"]; + if (_adaptorClassName) + [propertyList setObject: _adaptorClassName forKey: @"adaptorClassName"]; + if(_connectionDictionary) + [propertyList setObject: _connectionDictionary + forKey: @"connectionDictionary"]; + if(_userInfo) + [propertyList setObject: _userInfo forKey: @"userInfo"]; + if(_internalInfo) + [propertyList setObject: _internalInfo forKey: @"internalInfo"]; + if(_docComment) + [propertyList setObject: _docComment forKey: @"docComment"]; + + count = [_entities count]; + + if (count > 0) + { + NSMutableArray *entitiesArray = [NSMutableArray arrayWithCapacity: count]; + + [propertyList setObject: entitiesArray forKey: @"entities"]; + + for (i = 0; i < count; i++) + { + NSMutableDictionary *entityPList = [NSMutableDictionary dictionary]; + + [[_entities objectAtIndex: i] encodeIntoPropertyList: entityPList]; + [entitiesArray addObject: entityPList]; + } + } + + count = [_storedProcedures count]; + if (count > 0) + { + NSMutableArray *stArray = [NSMutableArray arrayWithCapacity: count]; + + [propertyList setObject: stArray forKey: @"entities"]; + for (i = 0; i < count; i++) + { + NSMutableDictionary *stPList = [NSMutableDictionary dictionary]; + + [[_storedProcedures objectAtIndex: i] + encodeIntoPropertyList: stPList]; + [stArray addObject: stPList]; + } + } +} + +@end + +@implementation EOModel (EOModelHidden) + +-(void) _classDescriptionNeeded: (NSNotification *)notification +{ + //TODO + NSString *notificationName = nil; + + EOFLOGObjectFnStart(); + + notificationName = [notification name]; + + NSDebugMLLog(@"gsdb", @"notificationName=%@", notificationName); + + if ([notificationName + isEqualToString: EOClassDescriptionNeededForClassNotification]) + { + Class aClass = [notification object]; + EOClassDescription *classDescription = nil; + EOEntity *entity = nil; + NSString *entityClassName = nil; + + NSDebugMLLog(@"gsdb", @"notification=%@ aClass=%@", notification, aClass); + NSAssert(aClass, @"No class"); + + entity = [self _entityForClass: aClass]; + + if (!entity) + { + NSAssert1((!GSObjCIsKindOf(aClass, [EOGenericRecord class])), + @"No entity for class %@", aClass); + } + else + { + classDescription = [entity classDescriptionForInstances]; + NSDebugMLLog(@"gsdb", @"classDescription=%@", classDescription); + + entityClassName = [entity className]; + NSDebugMLLog(@"gsdb",@"entityClassName=%@",entityClassName); + + [EOClassDescription registerClassDescription: classDescription + forClass: NSClassFromString(entityClassName)]; + + /* classDescription = [[EOClassDescription new] autorelease]; + NSDebugMLLog(@"gsdb", @"classDescription=%@ aClass=%@", classDescription, aClass); + [EOClassDescription registerClassDescription: classDescription + forClass: aClass]; + */ + } + } + else if ([notificationName + isEqualToString: EOClassDescriptionNeededForEntityNameNotification]) + { + //OK + EOClassDescription *classDescription; + NSString *entityName = [notification object]; + EOEntity *entity; + NSString *entityClassName; + + NSDebugMLLog(@"gsdb", @"notification=%@", notification); + NSDebugMLLog(@"gsdb", @"entityName=%@", entityName); + + NSAssert(entityName, @"No entity name");//?? + + entity = [self entityNamed: entityName]; + NSAssert1(entity, @"No entity named %@", entityName);//?? + + classDescription = [entity classDescriptionForInstances]; + NSDebugMLLog(@"gsdb", @"classDescription=%@", classDescription); + + entityClassName = [entity className]; + NSDebugMLLog(@"gsdb", @"entityClassName=%@", entityClassName); + + [EOClassDescription registerClassDescription: classDescription + forClass: NSClassFromString(entityClassName)];//?? + } + else if ([notificationName + isEqualToString: EOClassDescriptionNeededNotification]) + { + //TODO + } + else + { + //TODO + } + + EOFLOGObjectFnStop(); +} + +- (void)_resetPrototypeCache +{ + // TODO + [self notImplemented: _cmd]; +} + +- (BOOL)isPrototypesEntity: (id)param0 +{ + // TODO + [self notImplemented: _cmd]; + return NO; +} + +- (id)_instantiatedEntities +{ + // TODO + [self notImplemented: _cmd]; + return nil; +} + + +- (void)_setPath: (NSString*)path +{ + //OK + [self loadAllModelObjects]; + [self willChange]; + ASSIGN(_path,path); + [self setName: [path stringByDeletingPathExtension]];//VERIFY +} + +- (EOEntity*)_entityForClass: (Class)aClass +{ + NSString *className; + EOEntity *entity; + + EOFLOGObjectFnStart(); + + NSAssert(aClass, @"No class"); + NSAssert(_entitiesByClass, @"No _entitiesByClass"); + + className = NSStringFromClass(aClass); + NSDebugMLLog(@"gsdb", @"className=%@", className); + + entity = NSMapGet(_entitiesByClass, className); + NSDebugMLLog(@"gsdb", @"entity class=%@", [entity class]); + + if (entity) + { + entity = [self _verifyBuiltEntityObject: entity + named: nil]; + NSDebugMLLog(@"gsdb", @"entity=%@", entity); + } + else + { + NSDebugMLLog(@"gsdb", @"entity for class named=%@ not found", className); + NSDebugMLLog(@"gsdb", @"entities class names=%@", + NSAllMapTableKeys(_entitiesByClass)); + NSDebugMLLog(@"gsdb", @"entities entities names=%@", + NSAllMapTableValues(_entitiesByClass)); + NSDebugMLLog(@"gsdb", @"entities map=%@", + NSStringFromMapTable(_entitiesByClass)); + } + + EOFLOGObjectFnStop(); + + return entity; +} + +- (id)_childrenForEntityNamed: (id)param0 +{ + // TODO [self notImplemented:_cmd]; + return nil; +} + +- (void)_registerChild: (id)param0 + forParent: (id)param1 +{ + // TODO [self notImplemented:_cmd]; +} + +- (void)_setInheritanceLinks: (id)param0 +{ + // TODO + [self notImplemented: _cmd]; +} + +- (void)_removeEntity: (id)entity +{ + //should be ok + NSString *entityName = nil; + NSString *entityClassName = nil; + + if ([entity isKindOfClass: [EOEntity class]]) + { + entityName = [(EOEntity*)entity name]; + entityClassName = [entity className]; + } + else + { + entityName = [entity objectForKey: @"name"]; + entityClassName = [entity objectForKey: @"className"]; + } + + [_entitiesByName removeObjectForKey: entityName]; + + if (_entitiesByClass) + NSMapRemove(_entitiesByClass, entityClassName); + + DESTROY(_entities); +} + +- (EOEntity*)_addEntityWithPropertyList: (NSDictionary*)propertyList +{ + //OK + id children = nil; + EOEntity *entity = nil; + + NSAssert(propertyList, @"no propertyList"); + NSDebugMLLog(@"gsdb", @"propertyList=%@", propertyList); + + entity = [EOEntity entityWithPropertyList: propertyList + owner: self]; + + NSAssert2([entity className], @"Entity %p named %@ has no class name", + entity, [entity name]); + entity = [self _addEntity: entity]; + + children = [self _childrenForEntityNamed: [entity name]]; + + if (children) + { + [self notImplemented: _cmd];//TODO + //may be: self _registerChild:(id)param0 + // forParent:entity... + } + + [[NSNotificationCenter defaultCenter] + postNotificationName: @"EOEntityLoadedNotification" + object: entity]; + + return entity; +} + +- (void)_addFakeEntityWithPropertyList: (NSDictionary*)propertyList +{ + //OK + NSString *entityName; + NSString *className; + + NSAssert(propertyList, @"no propertyList"); + + entityName = [propertyList objectForKey: @"name"]; + className = [propertyList objectForKey: @"className"]; + + NSAssert1(entityName, @"No entity name in %@", propertyList); + NSAssert1(className, @"No class name in %@", propertyList); + + [self _setEntity: propertyList + forEntityName: entityName + className: className]; + + DESTROY(_entities); //To force rebuild +} + +- (id)_addEntity: (EOEntity*)entity +{ + //Seems OK + NSString *entityClassName; + + NSAssert(entity, @"No entity to add"); + NSDebugMLLog(@"gsdb", @"model _addEntity=%@", [entity name]); + + entityClassName = [entity className]; + NSAssert2(entityClassName, @"Entity %p named %@ has no class name", + entity, [entity name]); + + //May be returning a previous entity of that name if any ? + [self _setEntity: entity + forEntityName: [entity name] + className: entityClassName]; + [entity _setModel: self]; + + return entity; +} + +//entity can be a EOEntity or an entity PList +- (void)_setEntity: (id)entity + forEntityName: (NSString*)entityName + className: (NSString*)className +{ + NSAssert(entityName, @"No entity name"); + NSAssert(className, @"No class name"); + + //Seems OK + [_entitiesByName setObject: entity + forKey: entityName]; + + NSAssert(_entitiesByClass, @"No entities by class"); + + if (NSMapGet(_entitiesByClass, className)) + NSMapRemove(_entitiesByClass, className); + + NSMapInsertIfAbsent(_entitiesByClass, className, entity); +} + +@end + +@implementation EOModel (EOModelEditing) + +- (void)setName: (NSString *)name +{ + if (![name isEqualToString: _name]) + { + //TODO +/* + //??? + self retain; + self modelGroup; + //todo if modelgroup; +*/ + ASSIGN(_name, name); +/* + self modelGroup; + self release; +*/ + } +} + +- (void)setAdaptorName: (NSString *)adaptorName +{ + ASSIGN(_adaptorName, adaptorName); +} + +- (void)setConnectionDictionary: (NSDictionary *)connectionDictionary +{ + ASSIGN(_connectionDictionary, connectionDictionary); +} + +- (void)setUserInfo: (NSDictionary *)userInfo +{ + [self willChange]; + ASSIGN(_userInfo, userInfo); +} + +- (void)setDocComment: (NSString *)docComment +{ + [self willChange]; + ASSIGN(_docComment, docComment); +} + +- (void)addEntity: (EOEntity *)entity +{ + NSString *entityName = [entity name]; +// void *entitiesClass; +// int count; + NSString *className = nil; + + if ([self entityNamed: [entity name]]) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: \"%@\" already registered as entity name ", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + entityName]; + + if ([self createsMutableObjects]) + [(GCMutableArray *)_entities addObject: entity]; + else + { + _entities = [[[_entities autorelease] mutableCopy] autorelease]; + [(GCMutableArray *)_entities addObject: entity]; + _entities = [_entities copy]; + } + +/* + count = [_entities count]; + + entitiesClass = calloc(count, sizeof(id)); + memcpy(entitiesClass, _entitiesByClass, sizeof(Class)*(count-1)); + ((Class *)entitiesClass)[count-1] = [entity class]; + free(_entitiesByClass); + _entitiesByClass = entitiesClass; +*/ + NSAssert(_entitiesByClass, @"No _entitiesByClass"); + + className = [entity className]; + NSAssert1(className, @"No className in %@", entity); + + if (NSMapGet(_entitiesByClass, className)) + NSMapRemove(_entitiesByClass, className); + + NSMapInsertIfAbsent(_entitiesByClass, className, entity); + + [_entitiesByName setObject: entity + forKey: entityName]; + [entity setModel: self]; +} + +- (void)removeEntity: (EOEntity *)entity +{ +// unsigned int entityIndex = [_entities indexOfObject:entity]; + NSString *className = nil; +// void *entitiesClass=NULL; +// int count; + + [entity setModel: nil]; + [_entitiesByName removeObjectForKey: [entity name]]; + +/* count = [_entities count]-1; + if(count) + { + entitiesClass = calloc(count, sizeof(id)); + if(entityIndex) + memcpy(entitiesClass, _entitiesByClass, sizeof(id)*entityIndex); + if(count > entityIndex) + memcpy(&((int *)entitiesClass)[entityIndex], + &((int *)_entitiesByClass)[entityIndex+1], + sizeof(id)*(count-entityIndex)); + } + free(_entitiesByClass); + _entitiesByClass = entitiesClass; +*/ + NSAssert(_entitiesByClass, @"No _entitiesByClass"); + + className = [entity className]; + NSAssert1(className, @"No className in %@", entity); + NSMapRemove(_entitiesByClass, className); + + if ([self createsMutableObjects]) + [(GCMutableArray *)_entities removeObject: entity]; + else + { + _entities = [[_entities autorelease] mutableCopy]; + [(GCMutableArray *)_entities removeObject: entity]; + _entities = [[_entities autorelease] copy]; + } +} + +- (void)removeEntityAndReferences: (EOEntity *)entity; +{ + [self removeEntity: entity]; + // TODO; +} + +- (void)addStoredProcedure: (EOStoredProcedure *)storedProcedure +{ + if ([self storedProcedureNamed: [storedProcedure name]]) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: \"%@\" already registered as stored procedure name ", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + [storedProcedure name]]; + + if ([self createsMutableObjects]) + [(GCMutableArray *)_storedProcedures addObject: storedProcedure]; + else + { + _storedProcedures = [[[_storedProcedures autorelease] mutableCopy] + autorelease]; + [(GCMutableArray *)_storedProcedures addObject: storedProcedure]; + _storedProcedures = [_storedProcedures copy]; + } +} + +- (void)removeStoredProcedure: (EOStoredProcedure *)storedProcedure +{ + if([self createsMutableObjects]) + [(GCMutableArray *)_storedProcedures removeObject: storedProcedure]; + else + { + _storedProcedures = [[_storedProcedures autorelease] mutableCopy]; + [(GCMutableArray *)_storedProcedures removeObject: storedProcedure]; + _storedProcedures = [[_storedProcedures autorelease] copy]; + } +} + +- (void)setModelGroup: (EOModelGroup *)group +{ + EOFLOGObjectFnStart(); + +//call group _addSubEntitiesCache: + _group = group; + + EOFLOGObjectFnStop(); +} + +- (void)loadAllModelObjects +{ + NSArray *storedProcedures = [self storedProcedures]; + //TODO something if storedProcedures ? + NSArray *entities = [self entities]; + + //TODO something if entities ? + [self willChange]; +} + +- (NSArray *)referencesToProperty: property +{ + // TODO + [self notImplemented: _cmd]; + + return nil; +} + +- (NSArray *)externalModelsReferenced +{ + // TODO; + [self notImplemented: _cmd]; + + return nil; +} + +@end + + +@implementation EOModel (EOModelBeautifier) + +- (void)beautifyNames +{ + NSArray *listItems; + NSString *newString = [NSString string]; + int anz, i, count; + + EOFLOGObjectFnStartOrCond2(@"ModelingClasses", @"EOModel"); + + /* Makes the receiver's name conform to a standard convention. +Names that conform to this style are all lower-case except for the initial +letter of each embedded word other than the first, which is upper case. Thus, +"NAME" becomes "name", and "FIRST_NAME" becomes "firstName". */ + + NSLog(@"EOModel : beautifyNames is called"); + + if ((_name) && ([_name length] > 0)) + { + listItems = [_name componentsSeparatedByString: @"_"]; + newString = [newString stringByAppendingString: + [(NSString *)[listItems objectAtIndex: 0] + lowercaseString]]; + anz = [listItems count]; + + for (i = 1; i < anz; i++) + { + newString = [newString stringByAppendingString: + [(NSString *)[listItems objectAtIndex: i] + capitalizedString]]; + } + + // Exception abfangen + NS_DURING + { + // Model Name + [self setName: newString]; + + // Entites + if (_entities && (count = [_entities count])) + { + for (i = 0; i < count; i++) + [(EOEntity *)[_entities objectAtIndex:i] beautifyName]; + } + } + NS_HANDLER + NSLog(@"%@ in Class: EOEntity , Method: beautifyName >> error : %@", + [localException name], [localException reason]); + NS_ENDHANDLER; + } + + EOFLOGObjectFnStopOrCond2(@"ModelingClasses", @"EOModel"); +} + +@end + +@implementation EOModel (EOModelPrivate) + +- (void)setCreateMutableObjects: (BOOL)flag +{ + if (_flags.createsMutableObjects != flag) + { + _flags.createsMutableObjects = flag; + + if (_flags.createsMutableObjects) + _entities = [[_entities autorelease] mutableCopy]; + else + _entities = [[_entities autorelease] copy]; + } +} + +- (BOOL)createsMutableObjects +{ + return _flags.createsMutableObjects; +} + +- (EOEntity *)_verifyBuiltEntityObject: (id)entity + named: (NSString*)name +{ + if (![entity isKindOfClass: [EOEntity class]]) + { + [EOObserverCenter suppressObserverNotification]; + + NS_DURING + { + NSString *basePath = nil; + NSString *plistPathName = nil; + NSDictionary *propList = nil; + + NSDebugMLLog(@"gsdb", @"name=%@", name); + + if (!name && [entity isKindOfClass: [NSDictionary class]]) + name = [entity objectForKey: @"name"]; + + NSDebugMLLog(@"gsdb", @"name=%@", name); + NSAssert1(name, @"No name for entity %@", entity); + NSDebugMLLog(@"gsdb", @"[self path]=%@", [self path]); + + basePath = [[self class] findPathForModelNamed: [self path]]; + [[entity retain] autorelease]; //so it won't be lost in _removeEntity + + NSDebugMLLog(@"gsdb", @"basePath =%@", basePath); + + plistPathName = [[basePath stringByAppendingPathComponent: name] + stringByAppendingPathExtension: @"plist"]; + + NSDebugMLLog(@"gsdb", @"entity plistPathName =%@", plistPathName); + + propList = [NSDictionary dictionaryWithContentsOfFile: plistPathName]; + NSDebugMLLog(@"gsdb", @"entity propList=%@", propList); + + if (!propList) + { + if ([[NSFileManager defaultManager] + fileExistsAtPath: plistPathName]) + { + NSAssert1(NO, @"%@ is not a dictionary or is not readable.", + plistPathName); + } + else + { + propList = entity; + NSWarnLog(@"%@ doesn't exists. Using %@", + plistPathName, propList); + } + } + + [self _removeEntity: entity]; + NSDebugMLLog(@"gsdb", @"entity propList=%@", propList); + + entity = [self _addEntityWithPropertyList: propList]; + } + NS_HANDLER + { + [EOObserverCenter enableObserverNotification]; + [localException raise]; + } + NS_ENDHANDLER; + [EOObserverCenter enableObserverNotification]; + } + + return entity; +} + +@end /* EOModel (EOModelPrivate) */ diff --git a/EOAccess/EOModelGroup.h b/EOAccess/EOModelGroup.h new file mode 100644 index 0000000..df52a7f --- /dev/null +++ b/EOAccess/EOModelGroup.h @@ -0,0 +1,137 @@ +/* + EOModelGroup.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOModelGroup_h__ +#define __EOModelGroup_h__ + +#import +#import + + +@class EOModel; +@class EOEntity; +@class EORelationship; +@class EOGlobalID; +@class EOAttribute; + +@class EOStoredProcedure; +@interface EOModelGroup : GCObject +{ + NSMutableDictionary *_modelsByName; + id _delegate; + + struct { + unsigned int entityNamed:1; + unsigned int relationshipForRow:1; + unsigned int subEntityForEntity:1; + unsigned int failedToLookupClassNamed:1; + unsigned int classForObjectWithGlobalID:1; + unsigned int _RESERVED:27; + } _delegateRespondsTo; +} + ++ (EOModelGroup *)defaultGroup; ++ (void)setDefaultGroup: (EOModelGroup *)group; + ++ (EOModelGroup *)globalModelGroup; + ++ (void)setDelegate: (id)delegate; ++ (id)delegate; + +- (NSArray *)models; + +- (NSArray *)modelNames; + +- (EOModel *)modelNamed: (NSString *)name; + +- (EOModel *)modelWithPath: (NSString *)path; + +- (void)addModel: (EOModel *)model; + +- (EOModel*)addModelWithFile: (NSString *)path; + +- (void)removeModel: (EOModel *)model; + +- (EOEntity *)entityNamed: (NSString *)entityName; + +- (NSArray *)availablePrototypesForAdaptorName: (NSString *)adaptorName; +- (EOAttribute *)prototypeAttributeForAttribute: (EOAttribute *)attribute; + +- (EOEntity *)entityForObject: (id)object; + +- (void)loadAllModelObjects; + +- (id)delegate; +- (void)setDelegate: (id)delegate; +- (EOFetchSpecification *)fetchSpecificationNamed: (NSString *)fetchSpecName + entityNamed: (NSString *)entityName; + +- (EOStoredProcedure *)storedProcedureNamed: (NSString *)aName; + +@end + +// Notifications: +extern NSString *EOModelAddedNotification; +extern NSString *EOModelInvalidatedNotification; + + +@interface NSObject (EOModelGroupClassDelegation) + +- (EOModelGroup *)defaultModelGroup; + +@end + +@interface NSObject (EOModelGroupDelegation) + +- (EOModel *)modelGroup: (EOModelGroup *)group entityNamed: (NSString *)name; + +- (EORelationship *)entity: (EOEntity *)entity + relationshipForRow: (NSDictionary *)row + relationship: (EORelationship *)relationship; + +- (EOEntity *)subEntityForEntity: (EOEntity *)entity + primaryKey: (NSDictionary *)primaryKey + isFinal: (BOOL *)flag; + +- (Class)entity: (EOEntity *)entity +failedToLookupClassNamed: (NSString *)className; + +- (Class)entity: (EOEntity *)entity +classForObjectWithGlobalID: (EOGlobalID *)globalID; + +- (EOEntity *)relationship: (EORelationship *)relationship +failedToLookupDestinationNamed: (NSString *)entityName; + +@end + +@interface EOObjectStoreCoordinator (EOModelGroupSupport) + +- (void)setModelGroup: (EOModelGroup *)group; +- (EOModelGroup *)modelGroup; + +@end + +#endif diff --git a/EOAccess/EOModelGroup.m b/EOAccess/EOModelGroup.m new file mode 100644 index 0000000..d614886 --- /dev/null +++ b/EOAccess/EOModelGroup.m @@ -0,0 +1,403 @@ +/** + EOModelGroup.m EOModelGroup Class + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: June 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import + +#import +#import +#import +#import + +#import + + +@implementation EOModelGroup + + +NSString *EOModelAddedNotification = @"EOModelAddedNotification"; +NSString *EOModelInvalidatedNotification = @"EOModelInvalidatedNotification"; + + +static id classDelegate = nil; +static int delegateDefaultModelGroup = 0; +static EOModelGroup *defaultModelGroup = nil; + + ++ (EOModelGroup *)defaultGroup +{ + EOModelGroup *modelGroup = nil; + + EOFLOGObjectFnStart(); + + if (defaultModelGroup) + modelGroup = defaultModelGroup; + else if (delegateDefaultModelGroup) + modelGroup = [classDelegate defaultModelGroup]; + else + modelGroup = [EOModelGroup globalModelGroup]; + + if (!modelGroup) + { + NSLog(@"WARNING: No default Group"); + } + + EOFLOGObjectFnStop(); + + return modelGroup; +} + ++ (void)setDefaultGroup: (EOModelGroup *)group +{ + if (group != defaultModelGroup) + { + if (defaultModelGroup) + DESTROY(defaultModelGroup); + + if (delegateDefaultModelGroup) + group = [classDelegate defaultModelGroup]; + + ASSIGN(defaultModelGroup, group); + } +} + ++ (EOModelGroup *)globalModelGroup +{ + NSMutableArray *bundles = [NSMutableArray arrayWithCapacity: 2]; + NSBundle *bundle = nil; + NSArray *paths = nil; + NSEnumerator *pathsEnum = nil; + NSEnumerator *bundleEnum = nil; + EOModelGroup *group; + NSString *path = nil; + + EOFLOGObjectFnStart(); + + group = [EOModelGroup new]; + + [bundles addObjectsFromArray: [NSBundle allBundles]]; + [bundles addObjectsFromArray: [NSBundle allFrameworks]]; + + bundleEnum = [bundles objectEnumerator]; + while ((bundle = [bundleEnum nextObject])) + { + paths = [bundle pathsForResourcesOfType: @"eomodeld" + inDirectory: nil]; + + if (!paths) + { + NSLog(@"WARNING: paths for resource of type eomodeld in bundle %@",bundle); + } + + pathsEnum = [paths objectEnumerator]; + while ((path = [pathsEnum nextObject])) + { + NSLog(@"%@", path); + [group addModelWithFile: [path stringByDeletingPathExtension]]; + } + } + + EOFLOGObjectFnStop(); + + return [group autorelease]; // TODO release problem with EOModel +} + +/** returns a model group composed of all models in the resource directory +of the mainBundle, and all bundles and frameworks loaded into the app. +**/ + ++ (void)setDelegate: (id)delegate +{ + classDelegate = delegate; + + delegateDefaultModelGroup = [delegate respondsToSelector: + @selector(defaultModelGroup)]; +} + ++ (id)delegate +{ + return classDelegate; +} + + +- init +{ + self = [super init]; + + _modelsByName = [NSMutableDictionary new]; + + return self; +} + +- (void)dealloc +{ + DESTROY(_modelsByName); + + [super dealloc]; +} + +- (void)gcDecrementRefCountOfContainedObjects +{ + EOFLOGObjectFnStart(); + EOFLOGObjectFnStop(); +} + +- (BOOL)gcIncrementRefCountOfContainedObjects +{ + if (![super gcIncrementRefCountOfContainedObjects]) + return NO; + + return YES; +} + +- (NSArray *)models +{ + return [_modelsByName allValues]; +} + +- (NSArray *)modelNames +{ + return [_modelsByName allKeys]; +} + +- (EOModel *)modelNamed: (NSString *)name +{ + return [_modelsByName objectForKey: name]; +} + +- (EOModel *)modelWithPath: (NSString *)path +{ + NSEnumerator *modelEnum; + EOModel *model; + + modelEnum = [_modelsByName objectEnumerator]; + while ((model = [modelEnum nextObject])) + if ([[path stringByStandardizingPath] + isEqual: [[model path] stringByStandardizingPath]] == YES) + return model; + + return nil; +} + +- (void)addModel: (EOModel *)model +{ + //OK + //call model entityNames + NSString *modelName; + + EOFLOGObjectFnStart(); + + NSDebugMLLog(@"gsdb", @"model=%p", model); + + modelName = [model name]; + [model setModelGroup: self]; + + NSDebugMLLog(@"gsdb", @"model=%p name=%@", model, modelName); + + if (!modelName) + { + [NSException raise: NSInvalidArgumentException + format: [NSString stringWithFormat: + @"The model name is emtpy"]]; + } + + NSAssert1(modelName, @"No name for model %@", model); + + if ([_modelsByName objectForKey: modelName]) + { + [NSException raise: NSInvalidArgumentException + format: [NSString stringWithFormat: @"The modelname '%@' already exists in modelGroup", + modelName]]; + } + + [_modelsByName setObject: model + forKey: modelName]; + + NSDebugMLLog(@"gsdb", @"Notification for model:%p", model); + + [[NSNotificationCenter defaultCenter] + postNotificationName: EOModelAddedNotification + object: model]; + + EOFLOGObjectFnStop(); +} + +- (EOModel *)addModelWithFile: (NSString *)path +{ + EOModel *model; + + EOFLOGObjectFnStart(); + + model = [EOModel modelWithContentsOfFile: path]; + + NSDebugMLLog(@"gsdb", @"model=%p", model); + + if (model) + [self addModel: model]; + + EOFLOGObjectFnStop(); + + return model; +} + +- (void)removeModel: (EOModel *)model +{ + [_modelsByName removeObjectForKey: [model name]]; + [model setModelGroup: nil]; + + [[NSNotificationCenter defaultCenter] + postNotificationName: EOModelInvalidatedNotification + object: model]; +} + +- (EOEntity *)entityNamed: (NSString *)entityName +{ + NSEnumerator *modelEnum; + EOModel *model; + EOEntity *entity; + + modelEnum = [_modelsByName objectEnumerator]; + while ((model = [modelEnum nextObject])) + if ((entity = [model entityNamed: entityName])) + return entity; + + return nil; +} + +- (EOEntity *)entityForObject: (id)object +{ + NSEnumerator *modelEnum; + EOModel *model; + EOEntity *entity; + + modelEnum = [_modelsByName objectEnumerator]; + while ((model = [modelEnum nextObject])) + if ((entity = [model entityForObject: object])) + return entity; + + return nil; +} + +- (NSArray *)availablePrototypesForAdaptorName: (NSString *)adaptorName +{ + [self notImplemented: _cmd]; + return nil; +} + +- (EOAttribute *)prototypeAttributeForAttribute: (EOAttribute *)attribute +{ + [self notImplemented: _cmd]; + return nil; +} + +- (void)loadAllModelObjects +{ + NSEnumerator *modelEnum; + EOModel *model; + + modelEnum = [_modelsByName objectEnumerator]; + while ((model = [modelEnum nextObject])) + [model loadAllModelObjects]; +} + +- (id)delegate +{ + return _delegate; +} + +- (void)setDelegate: (id)delegate +{ + EOFLOGObjectFnStartOrCond2(@"ModelingClasses", @"EOModelGroup"); + + ASSIGN(_delegate, delegate); + + _delegateRespondsTo.entityNamed = + [_delegate respondsToSelector: @selector(modelGroup:entityNamed:)]; + _delegateRespondsTo.failedToLookupClassNamed = + [_delegate respondsToSelector: @selector(entity:failedToLookupClassNamed:)]; + _delegateRespondsTo.classForObjectWithGlobalID = + [_delegate respondsToSelector: @selector(entity:classForObjectWithGlobalID:)]; + _delegateRespondsTo.subEntityForEntity = + [_delegate respondsToSelector: @selector(subEntityForEntity:primaryKey:isFinal:)]; + _delegateRespondsTo.relationshipForRow = + [_delegate respondsToSelector: @selector(entity:relationshipForRow:relationship:)]; + + EOFLOGObjectFnStopOrCond2(@"ModelingClasses", @"EOModelGroup"); +} + +- (EOFetchSpecification *)fetchSpecificationNamed: (NSString *)fetchSpecName + entityNamed: (NSString *)entityName +{ + EOFetchSpecification *newFetchSpecification = nil; + EOEntity *anEntity; + + EOFLOGObjectFnStartOrCond2(@"ModelingClasses", @"EOModelGroup"); + + if (fetchSpecName + && entityName && (anEntity = [self entityNamed: entityName])) + { + newFetchSpecification = [anEntity fetchSpecificationNamed: fetchSpecName]; + } + + EOFLOGObjectFnStopOrCond2(@"ModelingClasses", @"EOModelGroup"); + + return newFetchSpecification; +} + +- (EOStoredProcedure *)storedProcedureNamed: (NSString *)aName +{ + EOStoredProcedure *newStoredProcedure = nil; + NSEnumerator *modelEnum; + EOModel *model; + + EOFLOGObjectFnStartOrCond2(@"ModelingClasses", @"EOModelGroup"); + + modelEnum = [_modelsByName objectEnumerator]; + while ((model = [modelEnum nextObject])) + { + if ((newStoredProcedure = [model storedProcedureNamed: aName])) + { + EOFLOGObjectFnStopOrCond2(@"ModelingClasses", @"EOModelGroup"); + + return newStoredProcedure; + } + } + + EOFLOGObjectFnStopOrCond2(@"ModelingClasses", @"EOModelGroup"); + + return nil; +} + +@end diff --git a/EOAccess/EOPropertyListEncoding.h b/EOAccess/EOPropertyListEncoding.h new file mode 100644 index 0000000..b0bb817 --- /dev/null +++ b/EOAccess/EOPropertyListEncoding.h @@ -0,0 +1,43 @@ +/* + EOPropertyListEncoding.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOPropertyListEncoding_h__ +#define __EOPropertyListEncoding_h__ + +#import + + +@protocol EOPropertyListEncoding + +- initWithPropertyList: (NSDictionary *)propertyList owner: (id)owner; + +- (void)awakeWithPropertyList: (NSDictionary *)propertyList; + +- (void)encodeIntoPropertyList: (NSMutableDictionary *)propertyList; + +@end + +#endif /* __EOPropertyListEncoding_h__ */ diff --git a/EOAccess/EORelationship.h b/EOAccess/EORelationship.h new file mode 100644 index 0000000..1b1d341 --- /dev/null +++ b/EOAccess/EORelationship.h @@ -0,0 +1,231 @@ +/* + EORelationship.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EORelationship_h__ +#define __EORelationship_h__ + +#import + +#import +#import + +#import +#import + +#import +#import + + +@class EOEntity; +@class EOAttribute; +@class EOExpressionArray; +@class EOMKKDSubsetMapping; + +typedef enum { + EOInnerJoin = 0, + EOFullOuterJoin, + EOLeftOuterJoin, + EORightOuterJoin +} EOJoinSemantic; + + +@interface EORelationship : GCObject +{ + NSString *_name; + EOQualifier *_qualifier; + NSMutableDictionary *_sourceNames; + NSMutableDictionary *_destinationNames; + NSDictionary *_userInfo; + NSDictionary *_internalInfo; + NSString *_docComment; + NSDictionary *_sourceToDestinationKeyMap; + unsigned int _batchCount; + EOJoinSemantic _joinSemantic; + + struct { + unsigned int isToMany:1; + unsigned int useBatchFaulting:1; + unsigned int deleteRule:2; + unsigned int isMandatory:1; + unsigned int ownsDestination:1; + unsigned int propagatesPrimaryKey:1; + unsigned int createsMutableObjects:1; + unsigned int isBidirectional:1; + unsigned int extraRefCount:23; + } _flags; + id _sourceRowToForeignKeyMapping; + + /* Garbage collectable objects */ + EOExpressionArray *_definitionArray; + + EORelationship *_inverseRelationship; + EORelationship *_hiddenInverseRelationship; + + EOEntity *_entity; + EOEntity *_destination; + GCMutableArray *_joins; + + /* Computed values */ + GCArray *_sourceAttributes; + GCArray *_destinationAttributes; + GCMutableArray *_componentRelationships;//Used ???? +} + ++ (id) relationshipWithPropertyList: (NSDictionary *)propertyList + owner: (id)owner; + +- (NSString *)name; + +- (EOEntity *)entity; + +- (EOEntity *)destinationEntity; + +- (NSString *)definition; + +- (BOOL)isFlattened; + +- (BOOL)isToMany; + +- (BOOL)isCompound; + +- (BOOL) isParentRelationship; + +- (NSArray *)sourceAttributes; + +- (NSArray *)destinationAttributes; + +- (NSArray *)joins; + +- (EOJoinSemantic)joinSemantic; +- (NSString*)joinSemanticString; + +- (NSArray *)componentRelationships; + +- (NSDictionary *)userInfo; + +- (BOOL)referencesProperty: (id)property; + +- (EODeleteRule)deleteRule; + +- (BOOL)isMandatory; + +- (BOOL)propagatesPrimaryKey; + +- (BOOL)isBidirectional; + +- (EORelationship *)hiddenInverseRelationship; +- (EORelationship *)inverseRelationship; + +- (EORelationship *)anyInverseRelationship; + +- (unsigned int)numberOfToManyFaultsToBatchFetch; + +- (BOOL)ownsDestination; +- (EOQualifier *)qualifierWithSourceRow: (NSDictionary *)sourceRow; + +@end + + +@interface EORelationship(EORelationshipEditing) +- (NSException *)validateName: (NSString *)name; +- (void)setName: (NSString *)name; +- (void)setDefinition: (NSString *)definition; +- (void)setEntity: (EOEntity *)entity; +- (void)setToMany: (BOOL)yn; +- (void)setPropagatesPrimaryKey: (BOOL)yn; +- (void)setIsBidirectional:(BOOL)yn; +- (void)setOwnsDestination: (BOOL)yn; +- (void)addJoin: (EOJoin *)join; +- (void)removeJoin: (EOJoin *)join; +- (void)setJoinSemantic: (EOJoinSemantic)joinSemantic; +- (void)setUserInfo: (NSDictionary *)dictionary; +- (void)setInternalInfo: (NSDictionary *)dictionary; +- (void)beautifyName; +- (void)setNumberOfToManyFaultsToBatchFetch: (unsigned int)size; +- (void)setDeleteRule: (EODeleteRule)deleteRule; +- (void)setIsMandatory: (BOOL)isMandatory; +- (void)setDocComment: (NSString *)docComment; + +@end + + +@interface EORelationship(EORelationshipValueMapping) + +- (NSException *)validateValue: (id *)valueP; + +@end + + +@interface EORelationship (EORelationshipPrivate) + +/*+ (EORelationship*)relationshipFromPropertyList: (id)propertyList + model: (EOModel*)model; +- (void)replaceStringsWithObjects; +- (void)initFlattenedRelationship; + +- (id)propertyList;*/ + +- (void)setCreateMutableObjects: (BOOL)flag; +- (BOOL)createsMutableObjects; +- (void)setInverseRelationship: (EORelationship*)relationship; +@end /* EORelationship (EORelationshipPrivate) */ + +@interface EORelationship (EORelationshipXX) + +- (NSArray*) _intermediateAttributes; +- (EORelationship*) lastRelationship; +- (EORelationship*) firstRelationship; +- (id) intermediateEntity; +- (BOOL) isMultiHop; +- (void) _setSourceToDestinationKeyMap: (id)param0; +- (id) qualifierForDBSnapshot: (id)param0; +- (id) primaryKeyForTargetRowFromSourceDBSnapshot: (id)param0; +- (NSString*)relationshipPath; +- (BOOL)isToManyToOne; +- (NSDictionary*)_sourceToDestinationKeyMap; +- (BOOL)foreignKeyInDestination; +@end + +@interface EORelationship (EORelationshipPrivate2) +- (BOOL) isPropagatesPrimaryKeyPossible; +- (id) qualifierOmittingAuxiliaryQualifierWithSourceRow: (id)param0; +- (id) auxiliaryQualifier; +- (void) setAuxiliaryQualifier: (id)param0; +- (id) _foreignKeyForSourceRow: (NSDictionary*)row; +- (EOMKKDSubsetMapping*) _sourceRowToForeignKeyMapping; +- (NSArray*) _sourceAttributeNames; +- (EOJoin*) joinForAttribute: (EOAttribute*)attribute; +- (void) _flushCache; +- (EOExpressionArray*) _definitionArray; +- (NSString*) _stringFromDeleteRule: (EODeleteRule)deleteRule; +- (EODeleteRule) _deleteRuleFromString: (NSString*)deleteRuleString; +- (NSDictionary*) _rightSideKeyMap; +- (NSDictionary*) _leftSideKeyMap; +- (EORelationship*)_substitutionRelationshipForRow: (NSDictionary*)row; +- (void) _joinsChanged; +@end + +#endif /* __EORelationship_h__ */ diff --git a/EOAccess/EORelationship.m b/EOAccess/EORelationship.m new file mode 100644 index 0000000..f3e530e --- /dev/null +++ b/EOAccess/EORelationship.m @@ -0,0 +1,2370 @@ +/** + EORelationship.m EORelationship + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + Author: Manuel Guesdon + Date: October 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import + +#import +#import + +#import +#import + +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#import +#import +#import +#import + + +@implementation EORelationship + +- init +{ +//OK + if ((self = [super init])) + { +/* _sourceNames = [NSMutableDictionary new]; + _destinationNames = [NSMutableDictionary new]; + _userInfo = [NSDictionary new]; + _sourceToDestinationKeyMap = [NSDictionary new]; + _joins = [GCMutableArray new]; +*/ + } + + return self; +} + +- (void)dealloc +{ + DESTROY(_name); + DESTROY(_qualifier); + DESTROY(_sourceNames); + DESTROY(_destinationNames); + DESTROY(_userInfo); + DESTROY(_internalInfo); + DESTROY(_docComment); + DESTROY(_sourceToDestinationKeyMap); + DESTROY(_sourceRowToForeignKeyMapping); + + [super dealloc]; +} + +- (void)gcDecrementRefCountOfContainedObjects +{ + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EORelationship", @"self=%@", self); + + EOFLOGObjectLevelArgs(@"EORelationship", + @"definitionArray gcDecrementRefCount"); + [(id)_definitionArray gcDecrementRefCount]; + + EOFLOGObjectLevelArgs(@"EORelationship", + @"_inverseRelationship gcDecrementRefCount"); + [_inverseRelationship gcDecrementRefCount]; + + EOFLOGObjectLevelArgs(@"EORelationship", + @"_hiddenInverseRelationship gcDecrementRefCount"); + [_hiddenInverseRelationship gcDecrementRefCount]; + + EOFLOGObjectLevelArgs(@"EORelationship", @"_entity gcDecrementRefCount"); + [_entity gcDecrementRefCount]; + + EOFLOGObjectLevelArgs(@"EORelationship", + @"_destination gcDecrementRefCount"); + [_destination gcDecrementRefCount]; + + EOFLOGObjectLevelArgs(@"EORelationship", + @"_joins %p gcDecrementRefCount (class=%@)", + _joins, [_joins class]); + [(id)_joins gcDecrementRefCount]; + + EOFLOGObjectLevelArgs(@"EORelationship", + @"_sourceAttributes gcDecrementRefCount (class=%@)", + [_sourceAttributes class]); + [(id)_sourceAttributes gcDecrementRefCount]; + + EOFLOGObjectLevelArgs(@"EORelationship", + @"_destinationAttributes gcDecrementRefCount (class=%@)", + [_destinationAttributes class]); + [(id)_destinationAttributes gcDecrementRefCount]; + + EOFLOGObjectLevelArgs(@"EORelationship", + @"_componentRelationships gcDecrementRefCount (class=%@)", + [_componentRelationships class]); + [(id)_componentRelationships gcDecrementRefCount]; + + EOFLOGObjectFnStop(); +} + +- (BOOL)gcIncrementRefCountOfContainedObjects +{ + if (![super gcIncrementRefCountOfContainedObjects]) + return NO; + + [(id)_definitionArray gcIncrementRefCount]; + [_inverseRelationship gcIncrementRefCount]; + [_hiddenInverseRelationship gcIncrementRefCount]; + [_entity gcIncrementRefCount]; + [_destination gcIncrementRefCount]; + [(id)_joins gcIncrementRefCount]; + [(id)_sourceAttributes gcIncrementRefCount]; + [(id)_destinationAttributes gcIncrementRefCount]; + [(id)_componentRelationships gcIncrementRefCount]; + + [(id)_definitionArray gcIncrementRefCountOfContainedObjects]; + [_inverseRelationship gcIncrementRefCountOfContainedObjects]; + [_hiddenInverseRelationship gcIncrementRefCountOfContainedObjects]; + [_entity gcIncrementRefCountOfContainedObjects]; + [_destination gcIncrementRefCountOfContainedObjects]; + [(id)_joins gcIncrementRefCountOfContainedObjects]; + [(id)_sourceAttributes gcIncrementRefCountOfContainedObjects]; + [(id)_destinationAttributes gcIncrementRefCountOfContainedObjects]; + [(id)_componentRelationships gcIncrementRefCountOfContainedObjects]; + + return YES; +} + +- (unsigned)hash +{ + return [_name hash]; +} + ++ (id) relationshipWithPropertyList: (NSDictionary *)propertyList + owner: (id)owner +{ + return [[[self alloc] initWithPropertyList: propertyList + owner: owner] autorelease]; +} + +- (id) initWithPropertyList: (NSDictionary *)propertyList + owner: (id)owner +{ + //Near OK + if ((self = [self init])) + { + NSString *joinSemanticString = nil; + EOModel *model; + NSString* destinationEntityName = nil; + EOEntity* destinationEntity = nil; + NSString* deleteRuleString = nil; + NSString* relationshipName; + + EOFLOGObjectFnStart(); + + model = [owner model]; + relationshipName = [propertyList objectForKey: @"name"]; + + [self setName: relationshipName]; + [self setEntity: owner]; + [self setCreateMutableObjects: YES]; + + destinationEntityName = [propertyList objectForKey: @"destination"]; + + if (destinationEntityName) //If not, this is because it's a definition + { + destinationEntity = [model entityNamed: destinationEntityName]; + ASSIGN(_destination, destinationEntity); + } + + [self setToMany: [[propertyList objectForKey: @"isToMany"] + isEqual: @"Y"]]; + [self setIsMandatory: [[propertyList objectForKey: @"isMandatory"] + isEqual:@"Y"]]; + [self setOwnsDestination: [[propertyList + objectForKey: @"ownsDestination"] + isEqual: @"Y"]]; + [self setPropagatesPrimaryKey: [[propertyList + objectForKey: @"propagatesPrimaryKey"] + isEqual: @"Y"]]; + [self setIsBidirectional: [[propertyList objectForKey: @"isBidirectional"] + isEqual: @"Y"]]; + + [self setUserInfo: [propertyList objectForKey: @"userInfo"]]; + + if(!_userInfo) + [self setUserInfo: [propertyList objectForKey: @"userDictionary"]]; + + [self setInternalInfo: [propertyList objectForKey: @"internalInfo"]]; + [self setDocComment: [propertyList objectForKey: @"docComment"]]; + + joinSemanticString = [propertyList objectForKey: @"joinSemantic"]; + if (joinSemanticString) + { + if ([joinSemanticString isEqual: @"EOInnerJoin"]) + [self setJoinSemantic: EOInnerJoin]; + else if ([joinSemanticString isEqual: @"EOFullOuterJoin"]) + [self setJoinSemantic: EOFullOuterJoin]; + else if ([joinSemanticString isEqual: @"EOLeftOuterJoin"]) + [self setJoinSemantic: EOLeftOuterJoin]; + else if ([joinSemanticString isEqual: @"EORightOuterJoin"]) + [self setJoinSemantic: EORightOuterJoin]; + else + { + EOFLOGObjectLevelArgs(@"EORelationship", @"Unknown joinSemanticString=%@. entityName=%@ relationshipName=%@", + joinSemanticString, + [owner name], + relationshipName); + NSEmitTODO(); //TODO + [self notImplemented: _cmd]; //TODO + } + } + else + { + if (destinationEntityName) + { + EOFLOGObjectLevelArgs(@"EORelationship", @"!joinSemanticString but destinationEntityName. entityName=%@ relationshipName=%@", + [owner name], + relationshipName); + NSEmitTODO(); //TODO + [self notImplemented: _cmd]; //TODO + } + } + + deleteRuleString = [propertyList objectForKey: @"deleteRule"]; + EOFLOGObjectLevelArgs(@"EORelationship", @"entityName=%@ relationshipName=%@ deleteRuleString=%@", + [owner name], + relationshipName, + deleteRuleString); + + if (deleteRuleString) + { + EODeleteRule deleteRule = [self _deleteRuleFromString: + deleteRuleString]; + EOFLOGObjectLevelArgs(@"EORelationship", + @"entityName=%@ relationshipName=%@ deleteRule=%d", + [owner name], + relationshipName, + (int)deleteRule); + NSAssert2(deleteRule >= 0 && deleteRule < 4, + @"Bad deleteRule numeric value: %@ (%d)", + deleteRuleString, + deleteRule); + + [self setDeleteRule: deleteRule]; + } + } + + EOFLOGObjectFnStop(); + + return self; +} + +- (void)awakeWithPropertyList: (NSDictionary *)propertyList //TODO +{ + //OK for definition + NSString *definition; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EORelationship", @"self=%@", self); + + definition = [propertyList objectForKey: @"definition"]; + + EOFLOGObjectLevelArgs(@"EORelationship", @"definition=%@", definition); + + if (definition) + { + [self setDefinition: definition]; + } + else + { + NSString *dataPath = [propertyList objectForKey: @"dataPath"]; + + EOFLOGObjectLevelArgs(@"EORelationship", @"dataPath=%@", dataPath); + + if (dataPath) + { + NSEmitTODO(); //TODO + [self notImplemented: _cmd]; // TODO + } + else + { + NSArray *joins = [propertyList objectForKey: @"joins"]; + int count = [joins count]; + + EOFLOGObjectLevelArgs(@"EORelationship", @"joins=%@", joins); + + if (count > 0) + { + int i; + + for (i = 0; i < count; i++) + { + NSDictionary *joinPList; + NSString *joinSemantic; + NSString *sourceAttributeName; + EOAttribute *sourceAttribute; + EOEntity *destinationEntity; + NSString *destinationAttributeName = nil; + EOAttribute *destinationAttribute = nil; + EOJoin *join = nil; + + joinPList = [joins objectAtIndex: i]; + joinSemantic = [joinPList objectForKey: @"joinSemantic"]; + + sourceAttributeName = [joinPList objectForKey: + @"sourceAttribute"]; + sourceAttribute = [_entity attributeNamed: + sourceAttributeName]; + + NSAssert4(sourceAttribute, @"No sourceAttribute named \"%@\" in entity \"%@\" in relationship %@\nEntity: %@", + sourceAttributeName, + [_entity name], + self, + _entity); + + destinationEntity = [self destinationEntity]; + destinationAttributeName = [joinPList + objectForKey: + @"destinationAttribute"]; + destinationAttribute = [destinationEntity + attributeNamed: + destinationAttributeName]; + + NSAssert4(destinationAttribute, @"No destinationAttribute named \"%@\" in entity \"%@\" in relationship %@\nEntity: %@", + destinationAttributeName, + [destinationEntity name], + self, + destinationEntity); + + NS_DURING + { + join = [EOJoin joinWithSourceAttribute: sourceAttribute + destinationAttribute: destinationAttribute]; + } + NS_HANDLER + { + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: cannot create join for relationship '%@': %@", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + [self name], + [localException reason]]; + } + NS_ENDHANDLER; + + EOFLOGObjectLevelArgs(@"EORelationship", @"join=%@", join); + + [self addJoin: join]; + } + } + /* + NSArray *array; + NSEnumerator *enumerator; + EOModel *model = [_entity model]; + id joinPList; + + if(_destination) + { + id destinationEntityName = [_destination autorelease]; + + _destination = [[model entityNamed:destinationEntityName] retain]; + if(!_destination) + { + NSEmitTODO(); //TODO + [self notImplemented:_cmd]; // TODO + } + } + */ + } + } + /* ?? + if(!(_destination || _definitionArray)) + { + NSEmitTODO(); //TODO + [self notImplemented:_cmd]; // TODO + }; + */ + + [self setCreateMutableObjects: NO]; //?? tc say yes, mirko no + + EOFLOGObjectFnStop(); +} + +- (void)encodeIntoPropertyList: (NSMutableDictionary *)propertyList +{ + //VERIFY + [propertyList setObject: [self name] + forKey: @"name"]; + + if ([self isFlattened]) + { + NSString *definition = [self definition]; + + [propertyList setObject: definition + forKey: @"definition"]; + } + else + { + [propertyList setObject: ([self isToMany] ? @"Y" : @"N") + forKey: @"isToMany"]; + [propertyList setObject: [self destinationEntity] + forKey: @"destination"]; + } + + if ([self isMandatory]) + [propertyList setObject: @"Y" + forKey: @"isMandatory"]; + + if ([self ownsDestination]) + { + NSEmitTODO(); //TODO + [self notImplemented: _cmd]; //TODO + } + + if ([self propagatesPrimaryKey]) + { + NSEmitTODO(); //TODO + [self notImplemented: _cmd]; //TODO + } + + { + int joinsCount = [_joins count]; + + if (joinsCount > 0) + { + NSMutableArray *joinsArray = [NSMutableArray array]; + int i; + + for(i = 0; i < joinsCount; i++) + { + NSMutableDictionary *joinDict = [NSMutableDictionary dictionary]; + EOJoin *join = [_joins objectAtIndex: i]; + + [joinDict setObject: [[join sourceAttribute] name] + forKey: @"sourceAttribute"]; + [joinDict setObject: [[join destinationAttribute] name] + forKey: @"destinationAttribute"]; + [joinsArray addObject: joinDict]; + } + + [propertyList setObject: joinsArray + forKey: @"joins"]; + } + + [propertyList setObject: [self joinSemanticString] + forKey: @"joinSemantic"]; + } +} + +- (NSString *)description +{ + NSString *dscr = nil; + + NS_DURING //Just for debugging + { + dscr = [NSString stringWithFormat: @"<%s %p - name=%@ entity=%@ destinationEntity=%@ definition=%@", + object_get_class_name(self), + (void*)self, + [self name], + [[self entity]name], + [[self destinationEntity] name], + [self definition]]; + + dscr = [dscr stringByAppendingFormat: @" userInfo=%@", + [self userInfo]]; + dscr = [dscr stringByAppendingFormat: @" joins=%@", + [self joins]]; + dscr = [dscr stringByAppendingFormat: @" sourceAttributes=%@", + [self sourceAttributes]]; + dscr = [dscr stringByAppendingFormat: @" destinationAttributes=%@", + [self destinationAttributes]]; + + /*TODO dscr = [dscr stringByAppendingFormat:@" componentRelationships=%@", + [self componentRelationships]];*/ + + dscr = [dscr stringByAppendingFormat: @" isCompound=%s isFlattened=%s isToMany=%s isBidirectional=%s>", + ([self isCompound] ? "YES" : "NO"), + ([self isFlattened] ? "YES" : "NO"), + ([self isToMany] ? "YES" : "NO"), + ([self isBidirectional] ? "YES" : "NO")]; + } + NS_HANDLER + { + NSLog(@"exception in EORelationship description: self=%p class=%@", + self, [self class]); + NSLog(@"exception in EORelationship definition: self name=%@ _definitionArray=%@", + [self name], _definitionArray); + NSLog(@"exception=%@", localException); + + [localException raise]; + } + NS_ENDHANDLER; + + return dscr; +} + +- (NSString *)name +{ + return _name; +} + +/** Returns the relationship's source entity. **/ +- (EOEntity *)entity +{ + return _entity; +} + +/** Returns the relationship's destination entity (direct destination entity or +destination entity of the last relationship in definition. **/ +- (EOEntity *)destinationEntity +{ + //OK + // May be we could cache destination ? Hard to do because klast relationship may have its destination entity change. + EOEntity *destinationEntity = _destination; + + if (!destinationEntity) + { + if ([self isFlattened]) + { + EORelationship *lastRelationship = [_definitionArray lastObject]; + + destinationEntity = [lastRelationship destinationEntity]; + + NSAssert3(destinationEntity, @"No destinationEntity in last relationship: %@ of relationship %@ in entity %@", + lastRelationship, self, [_entity name]); + } + } + else if ([destinationEntity isKindOfClass: [NSString class]] == YES) + destinationEntity = [[_entity model] + entityNamed: (NSString*)destinationEntity]; + + return destinationEntity; +} + +- (BOOL) isParentRelationship +{ + BOOL isParentRelationship = NO; + /*EOEntity *destinationEntity = [self destinationEntity]; + EOEntity *parentEntity = [_entity parentEntity];*///nil + + NSEmitTODO(); //TODO + // [self notImplemented:_cmd]; //TODO... + + return isParentRelationship; +} + +/** Returns YES when the relationship traverses at least two entities +(exemple: aRelationship.anotherRelationship), NO otherwise. +**/ +- (BOOL)isFlattened +{ + if (_definitionArray) + return [_definitionArray isFlattened]; + else + return NO; +} + +/** return YES if the relation if a to-many one, NO otherwise (please read books +to know what to-many mean :-) **/ +- (BOOL)isToMany +{ + return _flags.isToMany; +} + +/** Returns YES if the relationship have more than 1 join (i.e. join on more that one (sourceAttribute/destinationAttribute), NO otherwise (1 or less join) **/ + +- (BOOL)isCompound +{ + //OK + return [_joins count] > 1; +} + +- (NSArray *)joins +{ + return _joins; +} + +- (NSArray *)sourceAttributes +{ + //OK + if (!_sourceAttributes) + { + int i, count = [_joins count]; + + _sourceAttributes = [GCMutableArray new]; + + for (i = 0; i < count; i++) + { + EOJoin *join = [_joins objectAtIndex: i]; + [(GCMutableArray*)_sourceAttributes addObject: + [join sourceAttribute]]; + } + } + + return _sourceAttributes; +} + +- (NSArray *)destinationAttributes +{ + //OK + if (!_destinationAttributes) + { + int i, count = [_joins count]; + + _destinationAttributes = [GCMutableArray new]; + + for (i = 0; i < count; i++) + { + EOJoin *join = [_joins objectAtIndex: i]; + + [(GCMutableArray*)_destinationAttributes addObject: + [join destinationAttribute]]; + } + } + + return _destinationAttributes; +} + +- (EOJoinSemantic)joinSemantic +{ + return _joinSemantic; +} + +- (NSString*)joinSemanticString +{ + NSString *joinSemanticString = nil; + + switch ([self joinSemantic]) + { + case EOInnerJoin: + joinSemanticString = @"EOInnerJoin"; + break; + case EOFullOuterJoin: + joinSemanticString = @"EOFullOuterJoin"; + break; + case EOLeftOuterJoin: + joinSemanticString = @"EOLeftOuterJoin"; + break; + case EORightOuterJoin: + joinSemanticString = @"EORightOuterJoin"; + break; + default: + NSAssert1(NO, @"Unknwon join semantic code %d", + (int)[self joinSemantic]); + break; + } + + return joinSemanticString; +} + +- (NSArray *)componentRelationships +{ + if (!_componentRelationships) + { + return _definitionArray; //OK ?????? + NSEmitTODO(); //TODO + [self notImplemented: _cmd]; //TODO + } + + return _componentRelationships; +} + +- (NSDictionary *)userInfo +{ + return _userInfo; +} + +- (NSString *)docComment +{ + return _docComment; +} + +- (NSString *)definition +{ + //OK + NSString *definition = nil; + + NS_DURING //Just for debugging + { + definition = [_definitionArray valueForSQLExpression: nil]; + } + NS_HANDLER + { + NSLog(@"exception in EORelationship definition: self=%p class=%@", + self, [self class]); + NSLog(@"exception in EORelationship definition: self=%@ _definitionArray=%@", + self, _definitionArray); + NSLog(@"exception=%@", localException); + + [localException raise]; + } + NS_ENDHANDLER; + + return definition; +} + +/** Returns the value to use in an EOSQLExpression. **/ +- (NSString*) valueForSQLExpression: (EOSQLExpression*)sqlExpression +{ + EOFLOGObjectLevelArgs(@"EORelationship", @"EORelationship %p", self); + + NSEmitTODO(); //TODO +// return [self notImplemented:_cmd]; //TODO +//return name ?? + + return [self name]; +} + +- (BOOL)referencesProperty: (id)property +{ + BOOL referencesProperty = NO; + + NSEmitTODO(); //TODO + EOFLOGObjectLevelArgs(@"EORelationship", @"in referencesProperty:%@", + property); + + referencesProperty = ([[self sourceAttributes] + indexOfObject: property] != NSNotFound + || [[self destinationAttributes] + indexOfObject: property] != NSNotFound + || [[self componentRelationships] + indexOfObject: property] != NSNotFound); + + return referencesProperty; +} + +- (EODeleteRule)deleteRule +{ + EOFLOGObjectFnStart(); + EOFLOGObjectFnStop(); + + return _flags.deleteRule; +} + +- (BOOL)isMandatory +{ + return _flags.isMandatory; +} + +- (BOOL)propagatesPrimaryKey +{ + return _flags.propagatesPrimaryKey; +} + +- (BOOL)isBidirectional +{ + return _flags.isBidirectional; +} + +- (BOOL)isReciprocalToRelationship: (EORelationship *)relationship +{ + //Should be OK + BOOL isReciprocal = NO; + EOEntity *entity; + EOEntity *relationshipDestinationEntity = nil; + + EOFLOGObjectFnStart(); + + entity = [self entity]; //OK + relationshipDestinationEntity = [relationship destinationEntity]; + + EOFLOGObjectLevelArgs(@"EORelationship", @"entity %p name=%@", + entity, [entity name]); + EOFLOGObjectLevelArgs(@"EORelationship", + @"relationshipDestinationEntity %p name=%@", + relationshipDestinationEntity, + [relationshipDestinationEntity name]); + + if (entity == relationshipDestinationEntity) //Test like that ? + { + if ([self isFlattened]) //OK + { + if ([relationship isFlattened]) //OK + { + //Now compare each components in reversed order + NSArray *selfComponentRelationships = + [self componentRelationships]; + NSArray *relationshipComponentRelationships = + [relationship componentRelationships]; + int selfComponentRelationshipsCount = + [selfComponentRelationships count]; + int relationshipComponentRelationshipsCount = + [relationshipComponentRelationships count]; + + //May be we can imagine that they may not have the same number of components //TODO + if (selfComponentRelationshipsCount + == relationshipComponentRelationshipsCount) + { + int i, j; + BOOL foundEachInverseComponent = YES; + + for(i = (selfComponentRelationshipsCount - 1), j = 0; + foundEachInverseComponent && i >= 0; + i--, j++) + { + EORelationship *selfRel = + [selfComponentRelationships objectAtIndex: i]; + EORelationship *relationshipRel = + [relationshipComponentRelationships objectAtIndex: j]; + + foundEachInverseComponent = + [selfRel isReciprocalToRelationship: relationshipRel]; + } + + if (foundEachInverseComponent) + isReciprocal = YES; + } + } + else + { + NSEmitTODO(); //TODO + [self notImplemented: _cmd]; //TODO + } + } + else + { + //WO doens't test inverses entity + EOEntity *relationshipEntity = [relationship entity]; + EOEntity *destinationEntity = [self destinationEntity]; + + EOFLOGObjectLevelArgs(@"EORelationship", + @"relationshipEntity %p name=%@", + relationshipEntity, [relationshipEntity name]); + EOFLOGObjectLevelArgs(@"EORelationship", + @"destinationEntity %p name=%@", + destinationEntity, [destinationEntity name]); + + if (relationshipEntity == destinationEntity) + { + NSArray *joins = [self joins]; + NSArray *relationshipJoins = [relationship joins]; + int joinsCount = [joins count]; + int relationshipJoinsCount = [relationshipJoins count]; + + EOFLOGObjectLevelArgs(@"EORelationship", + @"joinsCount=%d,relationshipJoinsCount=%d", + joinsCount, relationshipJoinsCount); + + if (joinsCount == relationshipJoinsCount) + { + BOOL foundEachInverseJoin = YES; + int iJoin; + + for (iJoin = 0; + foundEachInverseJoin && iJoin < joinsCount; + iJoin++) + { + EOJoin *join = [joins objectAtIndex: iJoin]; + int iRelationshipJoin; + BOOL foundInverseJoin = NO; + + EOFLOGObjectLevelArgs(@"EORelationship", @"%d join=%@", + iJoin, join); + + for (iRelationshipJoin = 0; + !foundInverseJoin && iRelationshipJoin < joinsCount; + iRelationshipJoin++) + { + EOJoin *relationshipJoin = + [relationshipJoins objectAtIndex:iRelationshipJoin]; + + EOFLOGObjectLevelArgs(@"EORelationship", + @"%d relationshipJoin=%@", + iRelationshipJoin, + relationshipJoin); + + foundInverseJoin = [relationshipJoin + isReciprocalToJoin: join]; + + EOFLOGObjectLevelArgs(@"EORelationship", + @"%d foundInverseJoin=%s", + iRelationshipJoin, + (foundInverseJoin ? "YES" : "NO")); + } + + if (!foundInverseJoin) + foundEachInverseJoin = NO; + + EOFLOGObjectLevelArgs(@"EORelationship", + @"%d foundEachInverseJoin=%s", + iJoin, + (foundEachInverseJoin ? "YES" : "NO")); + } + + EOFLOGObjectLevelArgs(@"EORelationship", + @"foundEachInverseJoin=%s", + (foundEachInverseJoin ? "YES" : "NO")); + + if (foundEachInverseJoin) + isReciprocal = YES; + } + } + } + } + + EOFLOGObjectFnStop(); + + return isReciprocal; +} + +/** "Search only already created inverse relationship in destination entity +relationships. Nil if none" **/ +- (EORelationship *)inverseRelationship +{ + //OK + EOFLOGObjectFnStart(); + + if (!_inverseRelationship) + { + EOEntity *destinationEntity; + NSArray *destinationEntityRelationships; + + destinationEntity = [self destinationEntity]; + NSDebugLog(@"destinationEntity name=%@", [destinationEntity name]); + + destinationEntityRelationships = [destinationEntity relationships]; + + NSDebugLog(@"destinationEntityRelationships=%@", + destinationEntityRelationships); + + if ([destinationEntityRelationships count] > 0) + { + int i, count = [destinationEntityRelationships count]; + + for (i = 0; !_inverseRelationship && i < count; i++) + { + EORelationship *testRelationship = + [destinationEntityRelationships objectAtIndex: i]; + + NSDebugLog(@"testRelationship=%@", testRelationship); + + if ([self isReciprocalToRelationship: testRelationship]) + { + ASSIGN(_inverseRelationship, testRelationship); + } + } + } + + NSDebugLog(@"_inverseRelationship=%@", _inverseRelationship); + } + + EOFLOGObjectFnStop(); + + return _inverseRelationship; +} + +- (EORelationship *) _makeFlattenedInverseRelationship +{ + //OK + EORelationship *inverseRelationship = nil; + NSMutableString *invDefinition = nil; + NSString *name = nil; + int i, count; + + EOFLOGObjectFnStart(); + + NSAssert([self isFlattened], @"Not Flatten Relationship"); + EOFLOGObjectLevelArgs(@"EORelationship", @"add joins"); + + count = [_definitionArray count]; + + for (i = count - 1; i >= 0; i--) + { + EORelationship *rel = [_definitionArray objectAtIndex: i]; + EORelationship *invRel = [rel anyInverseRelationship]; + NSString *invRelName = [invRel name]; + + if (invDefinition) + { + if (i < (count - 1)) + [invDefinition appendString: @"."]; + + [invDefinition appendString: invRelName]; + } + else + invDefinition = [NSMutableString stringWithString: invRelName]; + } + + inverseRelationship = [[EORelationship new] autorelease]; + [inverseRelationship setEntity: [self destinationEntity]]; + + name = [NSString stringWithFormat: @"_eofInv_%@_%@", + [_entity name], + _name]; + [inverseRelationship setName: name]; + [inverseRelationship setDefinition: invDefinition]; + + EOFLOGObjectLevelArgs(@"EORelationship", @"add inverse rel"); + + [(NSMutableArray*)[[self destinationEntity] _hiddenRelationships] + addObject: inverseRelationship]; //not very clean !!! + EOFLOGObjectLevelArgs(@"EORelationship", @"set inverse rel"); + + [inverseRelationship setInverseRelationship: self]; + + EOFLOGObjectFnStop(); + + return inverseRelationship; +} + +- (EORelationship*) _makeInverseRelationship +{ + //OK + EORelationship *inverseRelationship; + NSString *name; + NSArray *joins = nil; + int i, count; + + EOFLOGObjectFnStart(); + + NSAssert(![self isFlattened], @"Flatten Relationship"); + + inverseRelationship = [[EORelationship new] autorelease]; + [inverseRelationship setEntity: _destination]; + + name = [NSString stringWithFormat: @"_eofInv_%@_%@", + [_entity name], + _name]; + [inverseRelationship setName: name]; + + joins = [self joins]; + count = [joins count]; + + EOFLOGObjectLevelArgs(@"EORelationship", @"add joins"); + + for (i = 0; i < count; i++) + { + EOJoin *join = [joins objectAtIndex: i]; + EOAttribute *sourceAttribute = [join sourceAttribute]; + EOAttribute *destinationAttribute = [join destinationAttribute]; + EOJoin *inverseJoin = [EOJoin joinWithSourceAttribute: + destinationAttribute //inverse souce<->destination attributes + destinationAttribute: sourceAttribute]; + + [inverseRelationship addJoin: inverseJoin]; + } + + EOFLOGObjectLevelArgs(@"EORelationship",@"add inverse rel"); + + [(NSMutableArray*)[[self destinationEntity] _hiddenRelationships] + addObject: inverseRelationship]; //not very clean !!! + + EOFLOGObjectLevelArgs(@"EORelationship", @"set inverse rel"); + + [inverseRelationship setInverseRelationship: self]; + + EOFLOGObjectFnStop(); + + return inverseRelationship; +} + +- (EORelationship*) hiddenInverseRelationship +{ + //OK + EOFLOGObjectFnStart(); + + if (!_hiddenInverseRelationship) + { + if ([self isFlattened]) + _hiddenInverseRelationship = [self _makeFlattenedInverseRelationship]; + else + _hiddenInverseRelationship = [self _makeInverseRelationship]; + } + + EOFLOGObjectFnStop(); + + return _hiddenInverseRelationship; +} + +- (EORelationship *)anyInverseRelationship +{ + //OK + EORelationship *inverseRelationship = [self inverseRelationship]; + + if (!inverseRelationship) + inverseRelationship = [self hiddenInverseRelationship]; + + return inverseRelationship; +} + +- (unsigned int)numberOfToManyFaultsToBatchFetch +{ + return _batchCount; +} + +- (BOOL)ownsDestination +{ + return _flags.ownsDestination; +} + +- (EOQualifier *)qualifierWithSourceRow: (NSDictionary *)sourceRow +{ + [self notImplemented: _cmd];//TODO + return nil; +} + +@end /* EORelationship */ + + +@implementation EORelationship (EORelationshipEditing) + +- (NSException *)validateName: (NSString *)name +{ + //Seems OK + const char *p, *s = [name cString]; + int exc = 0; + NSArray *storedProcedures = nil; + + if (!name || ![name length]) + exc++; + if (!exc) + { + p = s; + while (*p) + { + if(!isalnum(*p) && + *p != '@' && *p != '#' && *p != '_' && *p != '$') + { + exc++; + break; + } + p++; + } + if (!exc && *s == '$') + exc++; + + if ([[self entity] anyAttributeNamed: name]) + exc++; + else if ([[self entity] anyRelationshipNamed: name]) + exc++; + else if ((storedProcedures = [[[self entity] model] storedProcedures])) + { + NSEnumerator *stEnum = [storedProcedures objectEnumerator]; + EOStoredProcedure *st; + + while ((st = [stEnum nextObject])) + { + NSEnumerator *attrEnum; + EOAttribute *attr; + + attrEnum = [[st arguments] objectEnumerator]; + while ((attr = [attrEnum nextObject])) + { + if ([name isEqualToString: [attr name]]) + { + exc++; + break; + } + } + if (exc) + break; + } + } + } + + if (exc) + return [NSException exceptionWithName: NSInvalidArgumentException + reason: [NSString stringWithFormat: @"%@ -- %@ 0x%x: argument \"%@\" contains invalid chars", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + name] + userInfo: nil]; + else + return nil; +} + +- (void)setToMany: (BOOL)flag +{ + //OK + if ([self isFlattened]) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: receiver is a flattened relationship", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + + _flags.isToMany = flag; +} + +- (void)setName: (NSString *)name +{ + //OK + [[self validateName: name] raise]; + [self willChange]; + [_entity _setIsEdited]; + + ASSIGN(_name, name); +} + +- (void)setDefinition: (NSString *)definition +{ + //Near OK + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EORelationship", @"definition=%@", definition); + + if (definition) + { + [self _flushCache]; + [self willChange]; + + _flags.isToMany = NO; + + ASSIGN(_definitionArray, [_entity _parseRelationshipPath: definition]); + + EOFLOGObjectLevelArgs(@"EORelationship", @"_definitionArray=%@", _definitionArray); + EOFLOGObjectLevelArgs(@"EORelationship", @"[self definition]=%@", [self definition]); + + DESTROY(_destination); //No ? Assign destination ? + + { + //TODO VERIFY + //TODO better ? + int i, count = [_definitionArray count]; + + EOFLOGObjectLevelArgs(@"EORelationship", @"==> _definitionArray=%@", + _definitionArray); + + for (i = 0; !_flags.isToMany && i < count; i++) + { + EORelationship *rel = [_definitionArray objectAtIndex: i]; + + if ([rel isKindOfClass: [EORelationship class]]) + { + if ([rel isToMany]) + _flags.isToMany = YES; + } + else + break; + } + } + + [_entity _setIsEdited]; + } + + EOFLOGObjectFnStop(); +} + +- (void)setEntity: (EOEntity *)entity +{ + //OK + if (entity != _entity) + { + [self _flushCache]; + [self willChange]; + ASSIGN(_entity, entity); + } +} + +- (void)setUserInfo: (NSDictionary *)dictionary +{ + //OK + [self willChange]; + ASSIGN(_userInfo, dictionary); + [_entity _setIsEdited]; +} + +- (void)setInternalInfo: (NSDictionary *)dictionary +{ + //OK + [self willChange]; + ASSIGN(_internalInfo, dictionary); + [_entity _setIsEdited]; +} + +- (void)setDocComment: (NSString *)docComment +{ + //OK + [self willChange]; + ASSIGN(_docComment, docComment); + [_entity _setIsEdited]; +} + +- (void)setPropagatesPrimaryKey: (BOOL)flag +{ + //OK + if (_flags.propagatesPrimaryKey != flag) + [self willChange]; + + _flags.propagatesPrimaryKey = flag; +} + +- (void)setIsBidirectional: (BOOL)flag +{ + //OK + if (_flags.isBidirectional != flag) + [self willChange]; + + _flags.isBidirectional = flag; +} + +- (void)setOwnsDestination: (BOOL)flag +{ + if (_flags.ownsDestination != flag) + [self willChange]; + + _flags.ownsDestination = flag; +} + +- (void)addJoin: (EOJoin *)join +{ + EOAttribute *sourceAttribute = nil; + EOAttribute *destinationAttribute = nil; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EORelationship", @"Add join: %@\nto %@", join, self); + + if ([self isFlattened] == YES) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: receiver is a flattened relationship", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + else + { + EOEntity *destinationEntity = [self destinationEntity]; + EOEntity *sourceEntity = [self entity]; + + EOFLOGObjectLevelArgs(@"EORelationship", @"destinationEntity=%@", destinationEntity); + + if (!destinationEntity) + { + NSEmitTODO(); //TODO + EOFLOGObjectLevelArgs(@"EORelationship", @"self=%@", self); + //TODO ?? + }; + + sourceAttribute = [join sourceAttribute]; + + NSAssert3(sourceAttribute, @"No source attribute in join %@ in relationship %@ of entity %@", + join, + self, + sourceEntity); + + destinationAttribute = [join destinationAttribute]; + + NSAssert3(destinationAttribute, @"No destination attribute in join %@ in relationship %@ of entity %@", + join, + self, + sourceEntity); + + if ([sourceAttribute isFlattened] == YES + || [destinationAttribute isFlattened] == YES) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: join's attributes are flattened", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + else + { + EOEntity *joinDestinationEntity = [destinationAttribute entity]; + EOEntity *joinSourceEntity = [sourceAttribute entity]; + +/* if (destinationEntity && ![[destinationEntity name] isEqual:[joinSourceEntity name]]) + { + [NSException raise:NSInvalidArgumentException + format:@"%@ -- %@ 0x%x: join source entity (%@) is not equal to last join entity (%@)", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + [joinSourceEntity name], + [destinationEntity name]]; + }*/ + + if (sourceEntity + && ![[joinSourceEntity name] isEqual: [sourceEntity name]]) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x (%@): join source entity (%@) is not equal to relationship entity (%@)", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + [self name], + [joinSourceEntity name], + [sourceEntity name]]; + else if (destinationEntity + && ![[joinDestinationEntity name] + isEqual: [destinationEntity name]]) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x (%@): join destination entity (%@) is not equal to relationship destination entity (%@)", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + [self name], + [joinDestinationEntity name], + [destinationEntity name]]; + else + { + if ([_sourceAttributes count]) + { + EOAttribute *sourceAttribute = [join sourceAttribute]; + EOAttribute *destinationAttribute; + + destinationAttribute = [join destinationAttribute]; + + if (([_sourceAttributes indexOfObject: sourceAttribute] + != NSNotFound) + && ([_destinationAttributes + indexOfObject: destinationAttribute] + != NSNotFound)) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: TODO", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + } + + [self _flushCache]; + [self willChange]; + + EOFLOGObjectLevelArgs(@"EORelationship", @"really add"); + EOFLOGObjectLevelArgs(@"EORelationship", @"XXjoins %p class%@", + _joins, [_joins class]); + + if ([self createsMutableObjects]) + { + if (!_joins) + _joins = [GCMutableArray new]; + + [(GCMutableArray *)_joins addObject: join]; + + EOFLOGObjectLevelArgs(@"EORelationship", @"XXjoins %p class%@", + _joins, [_joins class]); + + //NO: will be recomputed [(GCMutableArray *)_sourceAttributes addObject:[join sourceAttribute]]; + //NO: will be recomputed [(GCMutableArray *)_destinationAttributes addObject:[join destinationAttribute]]; + } + else + { + if (_joins) + _joins = [[[_joins autorelease] + arrayByAddingObject: join] retain]; + else + _joins = [[GCArray arrayWithObject: join] retain]; + + EOFLOGObjectLevelArgs(@"EORelationship", @"XXjoins %p class%@", + _joins, [_joins class]); + + /*NO: will be recomputed _sourceAttributes = [[[_sourceAttributes autorelease] + arrayByAddingObject:[join sourceAttribute]] + retain]; + _destinationAttributes = [[[_destinationAttributes autorelease] + arrayByAddingObject: + [join destinationAttribute]] + retain]; + */ + } + + EOFLOGObjectLevelArgs(@"EORelationship", @"added"); + [self _joinsChanged]; + [_entity _setIsEdited]; + } + } + } + + EOFLOGObjectFnStop(); +} + +- (void)removeJoin: (EOJoin *)join +{ + EOFLOGObjectFnStart(); + + [self _flushCache]; + [self willChange]; + + if ([self isFlattened] == YES) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: receiver is a flattened relationship", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + else + { + if ([self createsMutableObjects]) + { + [(GCMutableArray *)_joins removeObject: join]; + + /*NO: will be recomputed [(GCMutableArray *)_sourceAttributes + removeObject:[join sourceAttribute]]; + [(GCMutableArray *)_destinationAttributes + removeObject:[join destinationAttribute]]; + */ + + EOFLOGObjectLevelArgs(@"EORelationship", @"XXjoins %p class%@", + _joins, [_joins class]); + } + else + { + [_joins autorelease]; + _joins = [_joins arrayByRemovingObject: join]; + + EOFLOGObjectLevelArgs(@"EORelationship", @"XXjoins %p class%@", + _joins, [_joins class]); + [_joins retain]; + + /* _joins = [[_joins autorelease] mutableCopy]; + [(GCMutableArray *)_joins removeObject:join]; + _joins = [[_joins autorelease] copy]; + */ + /*NO: will be recomputed + _sourceAttributes = [[_sourceAttributes autorelease] mutableCopy]; + [(GCMutableArray *)_sourceAttributes + removeObject:[join sourceAttribute]]; + _sourceAttributes = [[_sourceAttributes autorelease] copy]; + + _destinationAttributes = [[_destinationAttributes autorelease] + mutableCopy]; + [(GCMutableArray *)_destinationAttributes + removeObject:[join destinationAttribute]]; + _destinationAttributes = [[_destinationAttributes autorelease] copy]; + */ + } + + [self _joinsChanged]; + [_entity _setIsEdited]; + } + + EOFLOGObjectFnStop(); +} + +- (void)setJoinSemantic: (EOJoinSemantic)joinSemantic +{ + //OK + [self willChange]; + _joinSemantic = joinSemantic; +} + +- (void)beautifyName +{ + /*+ Make the name conform to the Next naming style + NAME -> name, FIRST_NAME -> firstName +*/ + NSArray *listItems; + NSString *newString = [NSString string]; + int anz, i; + + EOFLOGObjectFnStartOrCond2(@"ModelingClasses", @"EORelationship"); + + /* Makes the receiver's name conform to a standard convention. Names that +conform to this style are all lower-case except for the initial letter of +each embedded word other than the first, which is upper case. Thus, "NAME" +becomes "name", and "FIRST_NAME" becomes "firstName".*/ + + if ((_name) && ([_name length] > 0)) + { + listItems = [_name componentsSeparatedByString: @"_"]; + newString = [newString stringByAppendingString: + [[listItems objectAtIndex: 0] lowercaseString]]; + anz = [listItems count]; + + for (i = 1; i < anz; i++) + { + newString = [newString stringByAppendingString: + [[listItems objectAtIndex: i] + capitalizedString]]; + } + + // Exception abfangen + NS_DURING + { + [self setName:newString]; + } + NS_HANDLER + { + NSLog(@"%@ in Class: EORlationship , Method: beautifyName >> error : %@", + [localException name], [localException reason]); + } + NS_ENDHANDLER; + } + + EOFLOGObjectFnStopOrCond2(@"ModelingClasses", @"EORelationship"); +} + +- (void)setNumberOfToManyFaultsToBatchFetch: (unsigned int)size +{ + _batchCount = size; +} + +- (void)setDeleteRule: (EODeleteRule)deleteRule +{ + NSAssert1(deleteRule >= 0 && deleteRule < 4, + @"Bad deleteRule numeric value: %d", + deleteRule); + + _flags.deleteRule = deleteRule; +} + +- (void)setIsMandatory: (BOOL)isMandatory +{ + //OK + [self willChange]; + _flags.isMandatory = isMandatory; +} + +@end + +@implementation EORelationship(EORelationshipValueMapping) + +- (NSException *)validateValue: (id*)valueP +{ + //OK + NSException *exception = nil; + + EOFLOGObjectFnStart(); + + NSAssert(valueP, @"No value pointer"); + + if ([self isMandatory]) + { + BOOL isToMany = [self isToMany]; + + if ((isToMany == NO && *valueP == nil) + || (isToMany == YES && [*valueP count] == 0)) + { + EOEntity *destinationEntity = [self destinationEntity]; + EOEntity *entity = [self entity]; + + exception = [NSException validationExceptionWithFormat: + @"The %@ property of %@ must have a %@ assigned", + [self name], + [entity name], + [destinationEntity name]]; + /* //TODO userinfo: + userInfo { + EOValidatedObjectUserInfoKey = { + ... + }; + }; + EOValidatedPropertyUserInfoKey = quotationPlace; + }EOValidatedObjectUserInfoKey={ + ... + }; + } + EOValidatedPropertyUserInfoKey=quotationPlace + */ + } + } + + if (!exception) + { + NSEmitTODO(); //TODO + [self notImplemented:_cmd]; //TODO + } + + EOFLOGObjectFnStop(); + + return exception; +} + +@end + +@implementation EORelationship (EORelationshipPrivate) + +- (void)setCreateMutableObjects: (BOOL)flag +{ + if (_flags.createsMutableObjects != flag) + { + _flags.createsMutableObjects = flag; + + if (_flags.createsMutableObjects) + { + _joins = [[_joins autorelease] mutableCopy]; + + EOFLOGObjectLevelArgs(@"EORelationship", @"XXjoins %p class%@", + _joins, [_joins class]); + + DESTROY(_sourceAttributes); + DESTROY(_destinationAttributes); + /*Will be recomputed later _sourceAttributes = [[_sourceAttributes autorelease] mutableCopy]; + _destinationAttributes = [[_destinationAttributes autorelease] + mutableCopy]; + */ + } + else + { + _joins = [[_joins autorelease] copy]; + + EOFLOGObjectLevelArgs(@"EORelationship", @"XXjoins %p class%@", + _joins, [_joins class]); + + DESTROY(_sourceAttributes); + DESTROY(_destinationAttributes); + + /*Will be recomputed later _sourceAttributes = [[_sourceAttributes autorelease] copy]; + _destinationAttributes = [[_destinationAttributes autorelease] copy]; + */ + } + } +} + +- (BOOL)createsMutableObjects +{ + return _flags.createsMutableObjects; +} + +- (void)setInverseRelationship: (EORelationship*)relationship +{ + ASSIGN(_inverseRelationship,relationship); +} + +@end + +@implementation EORelationship (EORelationshipXX) + +- (NSArray*) _intermediateAttributes +{ + //Verify !! + NSMutableArray *intermediateAttributes; + EORelationship *rel; + NSArray *joins; + + //all this works on flattened and non flattened relationship. + intermediateAttributes = [NSMutableArray array]; + rel = [self firstRelationship]; + joins = [rel joins]; + //?? + [intermediateAttributes addObjectsFromArray: + [joins resultsOfPerformingSelector: + @selector(destinationAttribute)]]; + + rel = [self lastRelationship]; + joins = [rel joins]; + // attribute = [joins sourceAttribute]; + //?? + [intermediateAttributes addObjectsFromArray: + [joins resultsOfPerformingSelector: + @selector(sourceAttribute)]]; + + return [NSArray arrayWithArray: intermediateAttributes]; +} + +/** Return the last relationship if self is flattened, self otherwise. +**/ +- (EORelationship*) lastRelationship +{ + EORelationship *lastRel; + + if ([self isFlattened]) + { + NSAssert(!_definitionArray || [_definitionArray count] > 0, + @"Definition array is empty"); + + lastRel = [[self _definitionArray] lastObject]; + } + else + lastRel = self; + + return lastRel; +} + +/** Return the 1st relationship if self is flattened, self otherwise. +**/ +- (EORelationship*) firstRelationship +{ + EORelationship *firstRel; + + if ([self isFlattened]) + { + NSAssert(!_definitionArray || [_definitionArray count] > 0, + @"Definition array is empty"); + + firstRel = [[self _definitionArray] objectAtIndex: 0]; + } + else + firstRel = self; + + return firstRel; +} + +- (EOEntity*) intermediateEntity +{ + //TODO verify + id intermediateEntity = nil; + + if ([self isToManyToOne]) + { + int i, count = [_definitionArray count]; + + for (i = (count - 1); !intermediateEntity && i >= 0; i--) + { + EORelationship *rel = [_definitionArray objectAtIndex: i]; + + if ([rel isToMany]) + intermediateEntity = [rel destinationEntity]; + } + } + + return intermediateEntity; +} + +- (BOOL) isMultiHop +{ + //TODO verify + BOOL isMultiHop = NO; + + if ([self isFlattened]) + { + isMultiHop = YES; + } + + return isMultiHop; +} + +- (void) _setSourceToDestinationKeyMap: (id)param0 +{ + [self notImplemented: _cmd]; // TODO +} + +- (id) qualifierForDBSnapshot: (id)param0 +{ + return [self notImplemented: _cmd]; // TODO +} + +- (id) primaryKeyForTargetRowFromSourceDBSnapshot: (id)param0 +{ + return [self notImplemented:_cmd]; // TODO +} + +/** Return relationship path (like toRel1.toRel2) if self is flattened, slef name otherwise. +**/ +- (NSString*)relationshipPath +{ + //Seems OK + NSString *relationshipPath = nil; + + EOFLOGObjectFnStart(); + + if ([self isFlattened]) + { + int i, count = [_definitionArray count]; + + for (i = 0; i < count; i++) + { + EORelationship *relationship = [_definitionArray objectAtIndex: i]; + NSString *relationshipName = [relationship name]; + + if (relationshipPath) + [(NSMutableString*)relationshipPath appendString: @"."]; + else + relationshipPath = [NSMutableString string]; + + [(NSMutableString*)relationshipPath appendString: relationshipName]; + } + } + else + relationshipPath = [self name]; + + EOFLOGObjectFnStop(); + + return relationshipPath; +} + +-(BOOL)isToManyToOne +{ + BOOL isToManyToOne = NO; + + EOFLOGObjectFnStart(); + + if ([self isFlattened]) + { + BOOL isToMany = YES; + int count = [_definitionArray count]; + + if (count >= 2) + { + EORelationship *firstRelationship = [_definitionArray + objectAtIndex: 0]; + + isToMany = [firstRelationship isToMany]; + + if (!isToMany) + { + if ([firstRelationship isParentRelationship]) + { + NSEmitTODO(); //TODO + EOFLOGObjectLevelArgs(@"EORelationship", @"self=%@", self); + EOFLOGObjectLevelArgs(@"EORelationship", @"firstRelationship=%@", + firstRelationship); + + [self notImplemented: _cmd]; //TODO + } + } + + if (isToMany) + { + EORelationship *secondRelationship = [_definitionArray + objectAtIndex: 0]; + + if (![secondRelationship isToMany]) + { + EORelationship *invRel = [secondRelationship + anyInverseRelationship]; + + if (invRel) + secondRelationship = invRel; + + isToManyToOne = YES; + + if ([secondRelationship isParentRelationship]) + { + NSEmitTODO(); //TODO + EOFLOGObjectLevelArgs(@"EORelationship", @"self=%@", self); + EOFLOGObjectLevelArgs(@"EORelationship", @"secondRelationship=%@", + secondRelationship); + + [self notImplemented: _cmd]; //TODO + } + } + } + } + } + + EOFLOGObjectFnStop(); + + return isToManyToOne; +} + +-(NSDictionary*)_sourceToDestinationKeyMap +{ + //OK + EOFLOGObjectFnStart(); + + if (!_sourceToDestinationKeyMap) + { + NSString *relationshipPath = [self relationshipPath]; + + ASSIGN(_sourceToDestinationKeyMap, + [_entity _keyMapForRelationshipPath: relationshipPath]); + } + + EOFLOGObjectFnStop(); + + return _sourceToDestinationKeyMap; +} + +-(BOOL)foreignKeyInDestination +{ + BOOL foreignKeyInDestination = NO; + + EOFLOGObjectFnStart(); + + if ([self isToMany]) + { + foreignKeyInDestination = YES; + } + else + { + NSArray *sourceAttributes = [self sourceAttributes]; + NSArray *primaryKeyAttributes = [_entity primaryKeyAttributes]; + int sourceAttributesCount = [sourceAttributes count]; + int primaryKeyAttributesCount = [primaryKeyAttributes count]; + + EOFLOGObjectLevelArgs(@"EORelationship", @"sourceAttributes=%@", sourceAttributes); + EOFLOGObjectLevelArgs(@"EORelationship", @"primaryKeyAttributes=%@", primaryKeyAttributes); + + if (sourceAttributesCount > 0 && primaryKeyAttributesCount > 0) + { + int i; + + for (i = 0; + !foreignKeyInDestination && i < sourceAttributesCount; + i++) //TODO-VERIFY + { + EOAttribute *attribute = [sourceAttributes objectAtIndex: i]; + int pkAttrIndex = [primaryKeyAttributes + indexOfObjectIdenticalTo: attribute]; + + foreignKeyInDestination = (pkAttrIndex != NSNotFound); + } + } + } + + EOFLOGObjectFnStop(); + + EOFLOGObjectLevelArgs(@"EORelationship", @"foreignKeyInDestination=%s", + (foreignKeyInDestination ? "YES" : "NO")); + + return foreignKeyInDestination; +} + +@end + +@implementation EORelationship (EORelationshipPrivate2) + +- (BOOL) isPropagatesPrimaryKeyPossible +{ +/* + NSArray* joins=[self joins]; + NSArray* joinsSourceAttributes=[joins resultsOfPerformingSelector:@selector(sourceAttribute)]; + NSArray* joinsDestinationAttributes=[joins resultsOfPerformingSelector:@selector(destinationAttribute)]; + +joinsSourceAttributes names +sortedArrayUsingSelector:compare: + +result count + +joinsDestinationAttributes names +sortedArrayUsingSelector:compare: +inverseRelationship +inv entity [EOEntity]: +inv ventity primaryKeyAttributeNames +count +dest entity +dst entity primaryKeyAttributeNames + +*/ + EOFLOGObjectFnStart(); + + [self notImplemented: _cmd]; // TODO + + EOFLOGObjectFnStop(); + + return NO; +}; + +- (id) qualifierOmittingAuxiliaryQualifierWithSourceRow: (id)param0 +{ + return [self notImplemented: _cmd]; // TODO +} + +- (id) auxiliaryQualifier +{ + return nil; //[self notImplemented:_cmd]; // TODO +} + +- (void) setAuxiliaryQualifier: (id)param0 +{ + [self notImplemented:_cmd]; // TODO +} + +- (NSDictionary*) _foreignKeyForSourceRow: (NSDictionary*)row +{ + NSDictionary *foreignKey = nil; + EOMKKDSubsetMapping *sourceRowToForeignKeyMapping; + + EOFLOGObjectFnStart(); + + sourceRowToForeignKeyMapping = [self _sourceRowToForeignKeyMapping]; + + EOFLOGObjectLevelArgs(@"EORelationship", @"self=%@",self); + EOFLOGObjectLevelArgs(@"EORelationship", @"sourceRowToForeignKeyMapping=%@", + sourceRowToForeignKeyMapping); + + foreignKey = [EOMutableKnownKeyDictionary dictionaryFromDictionary: row + subsetMapping: + sourceRowToForeignKeyMapping]; + + EOFLOGObjectLevelArgs(@"EORelationship", @"row=%@\nforeignKey=%@", row, foreignKey); + + EOFLOGObjectFnStop(); + + return foreignKey; +} + +- (EOMKKDSubsetMapping*) _sourceRowToForeignKeyMapping +{ + EOFLOGObjectFnStart(); + + if (!_sourceRowToForeignKeyMapping) + { + NSDictionary *sourceToDestinationKeyMap; + NSArray *sourceKeys; + NSArray *destinationKeys; + EOEntity *destinationEntity; + EOMKKDInitializer *primaryKeyDictionaryInitializer; + EOMKKDInitializer *adaptorDictionaryInitializer; + EOMKKDSubsetMapping *sourceRowToForeignKeyMapping; + + sourceToDestinationKeyMap = [self _sourceToDestinationKeyMap]; + + EOFLOGObjectLevelArgs(@"EORelationship", @"sourceToDestinationKeyMap=%@", + sourceToDestinationKeyMap); + + sourceKeys = [sourceToDestinationKeyMap objectForKey: @"sourceKeys"]; + EOFLOGObjectLevelArgs(@"EORelationship", @"sourceKeys=%@", sourceKeys); + + destinationKeys = [sourceToDestinationKeyMap + objectForKey: @"destinationKeys"]; + EOFLOGObjectLevelArgs(@"EORelationship", @"destinationKeys=%@", destinationKeys); + + + destinationEntity = [self destinationEntity]; + primaryKeyDictionaryInitializer = [destinationEntity + _primaryKeyDictionaryInitializer]; + + EOFLOGObjectLevelArgs(@"EORelationship", @"destinationEntity named %@ primaryKeyDictionaryInitializer=%@", + [destinationEntity name], + primaryKeyDictionaryInitializer); + + adaptorDictionaryInitializer = [_entity _adaptorDictionaryInitializer]; + EOFLOGObjectLevelArgs(@"EORelationship",@"entity named %@ adaptorDictionaryInitializer=%@", + [_entity name], + adaptorDictionaryInitializer); + + sourceRowToForeignKeyMapping = + [primaryKeyDictionaryInitializer + subsetMappingForSourceDictionaryInitializer: + adaptorDictionaryInitializer + sourceKeys: sourceKeys + destinationKeys: destinationKeys]; + + ASSIGN(_sourceRowToForeignKeyMapping, sourceRowToForeignKeyMapping); + + EOFLOGObjectLevelArgs(@"EORelationship",@"%@ to %@: _sourceRowToForeignKeyMapping=%@", + [_entity name], + [destinationEntity name], + _sourceRowToForeignKeyMapping); + } + + EOFLOGObjectFnStop(); + + return _sourceRowToForeignKeyMapping; +} + +- (NSArray*) _sourceAttributeNames +{ + //Seems OK + return [[self sourceAttributes] + resultsOfPerformingSelector: @selector(name)]; +} + +- (EOJoin*) joinForAttribute: (EOAttribute*)attribute +{ + //OK + EOJoin *join = nil; + int i, count = [_joins count]; + + for (i = 0; !join && i < count; i++) + { + EOJoin *aJoin = [_joins objectAtIndex: i]; + EOAttribute *sourceAttribute = [aJoin sourceAttribute]; + + if ([attribute isEqual: sourceAttribute]) + join = aJoin; + } + + return join; +} + +- (void) _flushCache +{ + //VERIFY + //[self notImplemented:_cmd]; // TODO + DESTROY(_sourceAttributes); + DESTROY(_destinationAttributes); + DESTROY(_inverseRelationship); + DESTROY(_hiddenInverseRelationship); +} + +- (EOExpressionArray*) _definitionArray +{ + //VERIFY + return _definitionArray; +} + +- (NSString*) _stringFromDeleteRule: (EODeleteRule)deleteRule +{ + NSString *deleteRuleString = nil; + + switch(deleteRule) + { + case EODeleteRuleNullify: + deleteRuleString = @""; + break; + case EODeleteRuleCascade: + deleteRuleString = @""; + break; + case EODeleteRuleDeny: + deleteRuleString = @""; + break; + case EODeleteRuleNoAction: + deleteRuleString = @""; + break; + default: + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: invalid deleteRule code for relationship '%@': %d", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + [self name], + (int)deleteRule]; + break; + } + + return deleteRuleString; +} + +- (EODeleteRule) _deleteRuleFromString: (NSString*)deleteRuleString +{ + EODeleteRule deleteRule = 0; + + if ([deleteRuleString isEqualToString: @"EODeleteRuleNullify"]) + deleteRule = EODeleteRuleNullify; + else if ([deleteRuleString isEqualToString: @"EODeleteRuleCascade"]) + deleteRule = EODeleteRuleCascade; + else if ([deleteRuleString isEqualToString: @"EODeleteRuleDeny"]) + deleteRule = EODeleteRuleDeny; + else if ([deleteRuleString isEqualToString: @"EODeleteRuleNoAction"]) + deleteRule = EODeleteRuleNoAction; + else + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: invalid deleteRule string for relationship '%@': %@", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + [self name], + deleteRuleString]; + + return deleteRule; +} + +- (NSDictionary*) _rightSideKeyMap +{ + NSDictionary *keyMap = nil; + + NSEmitTODO(); //TODO + + [self notImplemented: _cmd]; // TODO + + if ([self isToManyToOne]) + { + int count = [_definitionArray count]; + + if (count >= 2) //?? + { + EORelationship *rel0 = [_definitionArray objectAtIndex: 0]; + + if ([rel0 isToMany]) //?? + { + EOEntity *entity = [rel0 destinationEntity]; + EORelationship *rel1 = [_definitionArray objectAtIndex: 1]; + + keyMap = [entity _keyMapForIdenticalKeyRelationshipPath: + [rel1 name]]; + } + } + } + + return keyMap; +} + +- (id) _leftSideKeyMap +{ + NSDictionary *keyMap = nil; + + NSEmitTODO(); //TODO + + [self notImplemented: _cmd]; // TODO + + if ([self isToManyToOne]) + { + int count = [_definitionArray count]; + + if (count >= 2) //?? + { + EORelationship *rel = [_definitionArray objectAtIndex: 0]; + + if ([rel isToMany]) //?? + { + EOEntity *entity = [rel entity]; + + keyMap = [entity _keyMapForIdenticalKeyRelationshipPath: + [rel name]]; + } + } + } + + return keyMap; +} + +- (EORelationship*)_substitutionRelationshipForRow: (NSDictionary*)row +{ + EOEntity *entity = [self entity]; + EOModel *model = [entity model]; + EOModelGroup *modelGroup = [model modelGroup]; + + if (modelGroup) + { + //?? + //NSEmitTODO(); //TODO + } + + return self; +} + +- (void) _joinsChanged +{ + //TODO VERIFY + int count; + + EOFLOGObjectFnStart(); + + count = [_joins count]; + + EOFLOGObjectLevelArgs(@"EORelationship", @"_joinsChanged:%@\nin %@", _joins, self); + + if (count > 0) + { + int i; + + for (i = 0; i < count; i++) + { + EOJoin *join = [_joins objectAtIndex: i]; + EOAttribute *destinationAttribute = [join destinationAttribute]; + EOEntity *destinationEntity = [destinationAttribute entity]; + + ASSIGN(_destination, destinationEntity); + } + } + else + { + DESTROY(_destination); + } +//_joins count + //[self notImplemented:_cmd]; // TODO-NOW +/* +join destinationAttribute +attr entity +*/ + + EOFLOGObjectFnStop(); +} + +@end diff --git a/EOAccess/EOSQLExpression.h b/EOAccess/EOSQLExpression.h new file mode 100644 index 0000000..42b48a6 --- /dev/null +++ b/EOAccess/EOSQLExpression.h @@ -0,0 +1,229 @@ +/* + EOSQLExpression.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOSQLExpression_h__ +#define __EOSQLExpression_h__ + +#import +#import + +#import +#import + +#import + +@class EOAttribute; +@class EOEntity; +@class EOQualifier; + + +extern NSString *EOBindVariableNameKey; +extern NSString *EOBindVariableAttributeKey; +extern NSString *EOBindVariableValueKey; +extern NSString *EOBindVariablePlaceHolderKey; +extern NSString *EOBindVariableColumnKey; + + +@interface EOSQLExpression : NSObject +{ + NSMutableDictionary *_aliasesByRelationshipPath; + EOEntity *_entity; + NSMutableString *_listString; + NSMutableString *_valueListString; + NSString *_whereClauseString; + NSMutableString *_joinClauseString; + NSMutableString *_orderByString; + NSMutableArray *_bindings; + NSMutableArray *_contextStack; + NSString *_statement; + BOOL _useAliases; +@private + int _alias; +} + ++ (EOSQLExpression *)expressionForString: (NSString *)string; + ++ (EOSQLExpression *)insertStatementForRow: (NSDictionary *)row + entity: (EOEntity *)entity; + ++ (EOSQLExpression *)updateStatementForRow: (NSDictionary *)row + qualifier: (EOQualifier *)qualifier + entity: (EOEntity *)entity; + ++ (EOSQLExpression *)deleteStatementWithQualifier: (EOQualifier *)qualifier + entity: entity; + ++ (EOSQLExpression *)selectStatementForAttributes: (NSArray *)attributes + lock: (BOOL)yn + fetchSpecification: (EOFetchSpecification *)fetchSpecification + entity: (EOEntity *)entity; + +- initWithEntity: (EOEntity *)entity; + +- (NSMutableDictionary *)aliasesByRelationshipPath; +- (EOEntity *)entity; + +- (NSMutableString *)listString; +- (NSMutableString *)valueList; +- (NSMutableString *)joinClauseString; +- (NSMutableString *)orderByString; +- (NSString *)whereClauseString; +- (NSString *)statement; +- (void)setStatement:(NSString *)statement; +- (NSString *)lockClause; + +- (NSString *)tableListWithRootEntity: (EOEntity *)entity; + + +- (void)prepareInsertExpressionWithRow: (NSDictionary *)row; + +- (void)prepareUpdateExpressionWithRow: (NSDictionary *)row + qualifier: (EOQualifier *)qualifier; + +- (void)prepareDeleteExpressionForQualifier: (EOQualifier *)qualifier; + +- (void)prepareSelectExpressionWithAttributes: (NSArray *)attributes + lock: (BOOL)yn + fetchSpecification: (EOFetchSpecification *)fetchSpecification; + +- (NSString *)assembleJoinClauseWithLeftName: (NSString *)leftName + rightName: (NSString *)rightName + joinSemantic: (EOJoinSemantic)semantic; + +- (void)addJoinClauseWithLeftName: (NSString *)leftName + rightName: (NSString *)rightName + joinSemantic: (EOJoinSemantic)semantic; + +- (void)joinExpression; + +- (NSString *)assembleInsertStatementWithRow: (NSDictionary *)row + tableList: (NSString *)tableList + columnList: (NSString *)columnList + valueList: (NSString *)valueList; + +- (NSString *)assembleUpdateStatementWithRow: (NSDictionary *)row + qualifier: (EOQualifier *)qualifier + tableList: (NSString *)tableList + updateList: (NSString *)updateList + whereClause: (NSString *)whereClause; + +- (NSString *)assembleDeleteStatementWithQualifier: (EOQualifier *)qualifier + tableList: (NSString *)tableList + whereClause: (NSString *)whereClause; + +- (NSString *)assembleSelectStatementWithAttributes: (NSArray *)attributes + lock: (BOOL)lock + qualifier: (EOQualifier *)qualifier + fetchOrder: (NSArray *)fetchOrder + selectString: (NSString *)selectString + columnList: (NSString *)columnList + tableList: (NSString *)tableList + whereClause: (NSString *)whereClause + joinClause: (NSString *)joinClause + orderByClause: (NSString *)orderByClause + lockClause: (NSString *)lockClause; + +- (void)addSelectListAttribute: (EOAttribute *)attribute; + +- (void)addInsertListAttribute: (EOAttribute *)attribute + value: (NSString *)value; + +- (void)addUpdateListAttribute: (EOAttribute *)attribute + value: (NSString *)value; + ++ (NSString *)formatStringValue: (NSString *)string; + ++ (NSString *)formatValue: (id)value forAttribute: (EOAttribute *)attribute; + ++ (NSString *)formatSQLString: (NSString *)sqlString + format: (NSString *)format; + +- (NSString *)sqlStringForConjoinedQualifiers: (NSArray *)qualifiers; +- (NSString *)sqlStringForDisjoinedQualifiers: (NSArray *)qualifiers; +- (NSString *)sqlStringForNegatedQualifier: (EOQualifier *)qualifier; +- (NSString *)sqlStringForKeyValueQualifier: (EOKeyValueQualifier *)qualifier; +- (NSString *)sqlStringForKeyComparisonQualifier: (EOKeyComparisonQualifier *)qualifier; +- (NSString *)sqlStringForValue: (NSString *)valueString + caseInsensitiveLikeKey: (NSString *)keyString; + +- (void)addOrderByAttributeOrdering: (EOSortOrdering *)sortOrdering; + ++ (BOOL)useQuotedExternalNames; ++ (void)setUseQuotedExternalNames: (BOOL)yn; +- (NSString *)externalNameQuoteCharacter; + +- (void)setUseAliases: (BOOL)useAliases; +- (BOOL)useAliases; + +- (NSString *)sqlStringForSchemaObjectName: (NSString *)name; + +- (NSString *)sqlStringForAttributeNamed: (NSString *)name; + +- (NSString *)sqlStringForSelector: (SEL)selector value: (id)value; + +- (NSString *)sqlStringForValue: (id)value attributeNamed: (NSString *)string; + +- (NSString *)sqlStringForAttribute: (EOAttribute *)anAttribute; + +- (NSString *)sqlStringForAttributePath: (NSArray *)path; + +- (void)appendItem: (NSString *)itemString + toListString: (NSMutableString *)listString; + ++ (NSString *)sqlPatternFromShellPattern: (NSString *)pattern; ++ (NSString *)sqlPatternFromShellPattern: (NSString *)pattern + withEscapeCharacter: (unichar)escapeCharacter; + + +- (NSMutableDictionary *)bindVariableDictionaryForAttribute: (EOAttribute *)attribute + value: value; + +- (BOOL)shouldUseBindVariableForAttribute: (EOAttribute *)att; + +- (BOOL)mustUseBindVariableForAttribute: (EOAttribute *)att; + ++ (BOOL)useBindVariables; ++ (void)setUseBindVariables: (BOOL)yn; + +- (NSArray *)bindVariableDictionaries; + +- (void)addBindVariableDictionary: (NSMutableDictionary *)binding; + +@end + +@interface NSString (EOSQLFormatting) + +- (NSString *)sqlString; + +@end + +@interface NSNumber (EOSQLFormatting) + +- (NSString *)sqlString; + +@end + +#endif /* __EOSQLExpression_h__ */ diff --git a/EOAccess/EOSQLExpression.m b/EOAccess/EOSQLExpression.m new file mode 100644 index 0000000..8d66720 --- /dev/null +++ b/EOAccess/EOSQLExpression.m @@ -0,0 +1,2878 @@ +/** + EOSQLExpression.m EOSQLExpression Class + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + Author: Manuel Guesdon + Date: November 2001 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#include + +#import + +#import +#import +#import +#import + +#import +#import +#import +#import + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#import +#import + + +NSString *EOBindVariableNameKey = @"EOBindVariableNameKey"; +NSString *EOBindVariableAttributeKey = @"EOBindVariableAttributeKey"; +NSString *EOBindVariableValueKey = @"EOBindVariableValueKey"; +NSString *EOBindVariablePlaceHolderKey = @"EOBindVariablePlaceHolderKey"; +NSString *EOBindVariableColumnKey = @"EOBindVariableColumnKey"; + + +@implementation EOSQLExpression + ++ (id)sqlExpressionWithEntity: (EOEntity *)entity +{ + return [[[self alloc] initWithEntity: entity] autorelease]; +} + +- (id) initWithEntity: (EOEntity *)entity +{ + if ((self = [self init])) + { + ASSIGN(_entity, entity); + + _aliasesByRelationshipPath = [NSMutableDictionary new]; + [_aliasesByRelationshipPath setObject: @"t0" + forKey: @""]; + _contextStack = [NSMutableArray new]; + [_contextStack addObject: @""]; + +/*NOT now _listString = [NSMutableString new]; + _valueListString = [NSMutableString new]; + _joinClauseString = [NSMutableString new]; + _orderByString = [NSMutableString new]; + _bindings = [NSMutableArray new]; +*/ + + _alias++; + } + + return self; +} + +- (void)dealloc +{ + DESTROY(_aliasesByRelationshipPath); + DESTROY(_entity); + DESTROY(_listString); + DESTROY(_valueListString); + DESTROY(_whereClauseString); + DESTROY(_joinClauseString); + DESTROY(_orderByString); + DESTROY(_bindings); + DESTROY(_contextStack); + DESTROY(_statement); + + [super dealloc]; +} + ++ (EOSQLExpression *)expressionForString: (NSString *)string +{ + EOSQLExpression *exp = [self sqlExpressionWithEntity: nil]; + + ASSIGN(exp->_statement, string); + + return exp; +} + ++ insertStatementForRow: (NSDictionary *)row + entity: (EOEntity *)entity +{ + EOSQLExpression *sqlExpression; + + if (!entity) + [NSException raise: NSInvalidArgumentException + format: @"EOSQLExpression: Entity of insertStatementForRow:entity: can't be the nil object"]; + + sqlExpression = [self sqlExpressionWithEntity: entity]; + + NSAssert(sqlExpression, @"No SQLExpression"); + + [sqlExpression setUseAliases: NO]; + + [sqlExpression prepareInsertExpressionWithRow: row]; + + return sqlExpression; +} + ++ updateStatementForRow: (NSDictionary *)row + qualifier: (EOQualifier *)qualifier + entity: (EOEntity *)entity +{ + EOSQLExpression *sqlExpression; + + if(!row || ![row count]) + [NSException raise: NSInvalidArgumentException + format: @"EOSQLExpression: Row of updateStatementForRow:qualifier:entity: " + @"can't be the nil object or empty dictionary"]; + + if (!qualifier) + [NSException raise: NSInvalidArgumentException + format: @"EOSQLExpression: Qualifier of updateStatementForRow:qualifier:entity: " + @"can't be the nil object"]; + + if (!entity) + [NSException raise: NSInvalidArgumentException + format: @"EOSQLExpression: Entity of updateStatementForRow:qualifier:entity: " + @"can't be the nil object"]; + + sqlExpression = [self sqlExpressionWithEntity: entity]; + + NSAssert(sqlExpression, @"No SQLExpression"); + + [sqlExpression setUseAliases: NO]; + + [sqlExpression prepareUpdateExpressionWithRow: row + qualifier: qualifier]; + + return sqlExpression; +} + ++ deleteStatementWithQualifier: (EOQualifier *)qualifier + entity: (EOEntity *)entity +{ + EOSQLExpression *sqlExpression; + + if (!qualifier) + [NSException raise: NSInvalidArgumentException + format: @"EOSQLExpression: Qualifier of deleteStatementWithQualifier:entity: " + @"can't be the nil object"]; + + if (!entity) + [NSException raise: NSInvalidArgumentException + format: @"EOSQLExpression: Entity of deleteStatementWithQualifier:entity: " + @"can't be the nil object"]; + + sqlExpression = [self sqlExpressionWithEntity: entity]; + + [sqlExpression prepareDeleteExpressionForQualifier: qualifier]; + + return sqlExpression; +} + ++ selectStatementForAttributes: (NSArray *)attributes + lock: (BOOL)flag + fetchSpecification: (EOFetchSpecification *)fetchSpecification + entity: (EOEntity *)entity +{ + EOSQLExpression *sqlExpression; + + if (!attributes || ![attributes count]) + [NSException raise: NSInvalidArgumentException + format: @"EOSQLExpression: Attributes of selectStatementForAttributes:lock:fetchSpecification:entity: " + @"can't be the nil object or empty array"]; + + if (!fetchSpecification) + [NSException raise: NSInvalidArgumentException + format: @"EOSQLExpression: FetchSpecification of selectStatementForAttributes:lock:fetchSpecification:entity: " + @"can't be the nil object"]; + + if (!entity) + [NSException raise: NSInvalidArgumentException + format: @"EOSQLExpression: Entity of selectStatementForAttributes:lock:fetchSpecification:entity: " + @"can't be the nil object"]; + + sqlExpression = [self sqlExpressionWithEntity: entity]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sqlExpression=%@", + sqlExpression); + + [sqlExpression setUseAliases: YES]; + [sqlExpression prepareSelectExpressionWithAttributes: attributes + lock: flag + fetchSpecification: fetchSpecification]; + + return sqlExpression; +} + +- (NSMutableDictionary *)aliasesByRelationshipPath +{ + return _aliasesByRelationshipPath; +} + +- (EOEntity *)entity +{ + return _entity; +} + +- (NSMutableString *)listString +{ + //OK + if (!_listString) + _listString = [NSMutableString new]; + + return _listString; +} + +- (NSMutableString *)valueList +{ + if (!_valueListString) + _valueListString = [NSMutableString new]; + + return _valueListString; +} + +- (NSMutableString *)joinClauseString +{ + if (!_joinClauseString) + _joinClauseString = [NSMutableString new]; + + return _joinClauseString; +} + +- (NSMutableString *)orderByString +{ + //OK + if (!_orderByString) + _orderByString = [NSMutableString new]; + + return _orderByString; +} + +- (NSString *)whereClauseString +{ + if (!_whereClauseString) + _whereClauseString = [NSMutableString new]; + + return _whereClauseString; +} + +- (NSString *)statement +{ + return _statement; +} + +- (void)setStatement:(NSString *)statement +{ + ASSIGN(_statement, statement); +} + +- (NSString *)lockClause +{ + [self subclassResponsibility: _cmd]; + + return nil; +} + +- (NSString *)tableListWithRootEntity: (EOEntity*)entity +{ +//self useAliases //ret 1 for select,0 for insert +//enity externalName +//self sqlStringForSchemaObjectName:eznti extnam//not always +// insert: ret quotation_place ?? / select: ret quotation_place t0 + + NSMutableString *entitiesString = [NSMutableString string]; + NSEnumerator *relationshipEnum; + NSString *relationshipPath; + EOEntity *currentEntity; + int i = 0; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"entity=%@", entity); + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"_aliasesByRelationshipPath=%@", + _aliasesByRelationshipPath); + + relationshipEnum = [_aliasesByRelationshipPath keyEnumerator]; + while ((relationshipPath = [relationshipEnum nextObject])) + { + currentEntity = entity; + + if (i) + [entitiesString appendString: @", "]; + + if ([relationshipPath isEqualToString: @""]) + { + NSString *externalName = [currentEntity externalName]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", + @"entity %p named %@: externalName=%@", + currentEntity, [currentEntity name], + externalName); + + [entitiesString appendString: externalName]; + + if (_useAliases) + [entitiesString appendFormat: @" %@", + [_aliasesByRelationshipPath + objectForKey: relationshipPath]]; + } + else + { + NSEnumerator *defEnum = nil; + NSArray *defArray = nil; + NSString *relationshipString; + NSString *externalName = nil; + + defArray = [relationshipPath componentsSeparatedByString: @"."]; + defEnum = [defArray objectEnumerator]; + + while ((relationshipString = [defEnum nextObject])) + { + currentEntity = [[currentEntity + relationshipNamed: relationshipString] + destinationEntity]; + } + + externalName = [currentEntity externalName]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", + @"entity %p named %@: externalName=%@", + currentEntity, [currentEntity name], + externalName); + + [entitiesString appendString: externalName]; + + if (_useAliases) + { + NSString *alias = [_aliasesByRelationshipPath + objectForKey: relationshipPath]; + + [entitiesString appendFormat: @" %@",alias]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", + @"appending alias %@ in entitiesString", + alias); + } + } + + i++; + } + + EOFLOGObjectFnStop(); + + return entitiesString; +} + +- (void)prepareInsertExpressionWithRow: (NSDictionary *)row +{ + //OK + EOEntity *rootEntity = nil; + NSString *tableList = nil; + NSEnumerator *rowEnum; + NSString *attributeName; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"row=%@", row); + + NS_DURING //Debugging Purpose + { + rowEnum = [row keyEnumerator]; + while ((attributeName = [rowEnum nextObject])) + { + EOAttribute *attribute = [_entity anyAttributeNamed: attributeName]; + id rowValue = [row objectForKey: attributeName]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"attribute name=%@", + attributeName); + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"rowValue=%@", rowValue); + +/*NO: in addInsertListAttribute id value=[self sqlStringForValue:rowValue + attributeNamed:attributeName];*/ + + [self addInsertListAttribute: attribute + value: rowValue]; + } + } + NS_HANDLER + { + NSDebugMLog(@"EXCEPTION %@", localException); + [localException raise]; + } + NS_ENDHANDLER; + + NS_DURING //Debugging Purpose + { + rootEntity = [self _rootEntityForExpression]; + tableList = [self tableListWithRootEntity: _entity]; + + ASSIGN(_statement, [self assembleInsertStatementWithRow: row + tableList: tableList + columnList: _listString + valueList: _valueListString]); + } + NS_HANDLER + { + NSDebugMLog(@"EXCEPTION %@", localException); + [localException raise]; + } + NS_ENDHANDLER; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"_statement=%@", _statement); + + EOFLOGObjectFnStop(); +} + +- (void)prepareUpdateExpressionWithRow: (NSDictionary *)row + qualifier: (EOQualifier *)qualifier +{ + //OK + EOEntity *rootEntity = nil; + NSString *whereClauseString = nil; + NSString *tableList = nil; + NSString *statement = nil; + NSEnumerator *rowEnum; + NSString *attributeName; + + EOFLOGObjectFnStart(); + + rowEnum = [row keyEnumerator]; + while ((attributeName = [rowEnum nextObject])) + { + id attribute = [_entity attributeNamed: attributeName]; + id value = [row objectForKey: attributeName]; + + [self addUpdateListAttribute: attribute + value: value]; + } + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"qualifier=%@", qualifier); + + whereClauseString = [()qualifier sqlStringForSQLExpression: self]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"whereClauseString=%@", + whereClauseString); + + ASSIGN(_whereClauseString, whereClauseString); + + rootEntity = [self _rootEntityForExpression]; + tableList = [self tableListWithRootEntity: rootEntity]; + statement = [self assembleUpdateStatementWithRow: row + qualifier: qualifier + tableList: tableList + updateList: _listString + whereClause: whereClauseString]; + + ASSIGN(_statement, statement); + + EOFLOGObjectFnStop(); +} + +- (void)prepareDeleteExpressionForQualifier: (EOQualifier *)qualifier +{ + ASSIGN(_whereClauseString, [(id)qualifier sqlStringForSQLExpression: self]); + + ASSIGN(_statement, [self assembleDeleteStatementWithQualifier: qualifier + tableList: [self tableListWithRootEntity: _entity] + whereClause: ([_whereClauseString length] ? + _whereClauseString : nil)]); +} + +/* +//TC: +- (void)prepareSelectExpressionWithAttributes:(NSArray *)attributes + lock:(BOOL)flag + fetchSpecification:(EOFetchSpecification *)fetchSpecification +{ + NSEnumerator *attrEnum, *sortEnum; + EOAttribute *attribute; + EOSortOrdering *sort; + NSString *tableList; + NSString *lockClause = nil; + NSArray *sortOrderings; + + EOFLOGObjectFnStartOrCond(@"EOSQLExpression"); + + // Turbocat (RawRow Additions) + if ([fetchSpecification rawRowKeyPaths]) { + + // fill _aliasesByRelationshipPath before calling addSelectListAttribute + + NSEnumerator *keyPathEnum = [[fetchSpecification rawRowKeyPaths] objectEnumerator]; + NSString *keyPath; + EOExpressionArray *expressionArray; + + while (keyPath = [keyPathEnum nextObject]) { + if([keyPath isNameOfARelationshipPath]) { + + // get relationships + NSString *newKeyPath = [keyPath stringByDeletingPathExtension]; // cut attributename + + if (![_aliasesByRelationshipPath objectForKey:newKeyPath]) { + //int count = [[_aliasesByRelationshipPath allKeys] count]; + NSString *prefix = [NSString stringWithFormat:@"t%d",_alias++]; + + [_aliasesByRelationshipPath setObject:prefix forKey:newKeyPath]; + } + } + } + //NSLog(@"_aliasesByRelationshipPath = %@", _aliasesByRelationshipPath); + } // Turbocat (RawRow Additions) + + attrEnum = [attributes objectEnumerator]; + while((attribute = [attrEnum nextObject])) + { + [self addSelectListAttribute:attribute]; + } + + ASSIGN(_whereClauseString, [(id)[fetchSpecification qualifier] + sqlStringForSQLExpression:self]); + + sortOrderings = [fetchSpecification sortOrderings]; + + sortEnum = [sortOrderings objectEnumerator]; + while((sort = [sortEnum nextObject])) + [self addOrderByAttributeOrdering:sort]; + + [self joinExpression]; + tableList = [self tableListWithRootEntity:_entity]; + if(flag) lockClause = [self lockClause]; + + ASSIGN(_statement, [self assembleSelectStatementWithAttributes:attributes + lock:flag + qualifier:[fetchSpecification qualifier] + fetchOrder:sortOrderings + selectString:nil //TODO + columnList:_listString + tableList:tableList + whereClause:([_whereClauseString length] ? + _whereClauseString : nil) + joinClause:([_joinClauseString length] ? + _joinClauseString : nil) + orderByClause:([_orderByString length] ? + _orderByString : nil) + lockClause:lockClause]); + + EOFLOGObjectFnStopOrCond(@"EOSQLExpression"); +} +*/ + +- (void)prepareSelectExpressionWithAttributes: (NSArray *)attributes + lock: (BOOL)lockFlag + fetchSpecification: (EOFetchSpecification *)fetchSpecification +{ + EOQualifier *fetchQualifier = nil; + EOQualifier *restrictingQualifier = nil; + NSString *whereClauseString = nil; + NSArray *sortOrderings = nil; + EOEntity *rootEntity = nil; + NSString *tableList = nil; + NSString *lockClauseString = nil; + BOOL usesDistinct = NO; + NSString *statement = nil; + NSString *selectCommand = nil; + //Add Attributes to listString + int i, count = [attributes count]; + + EOFLOGObjectFnStart(); + + //OK + for (i = 0; i < count; i++) + { + EOAttribute *attribute = [attributes objectAtIndex: i]; + + if ([attribute isFlattened]) + { + NSEmitTODO(); //TODO??? + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"flattened attribute=%@", + attribute); + } + else + [self addSelectListAttribute: attribute]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"_listString=%@", + _listString); + } + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"_listString=%@", _listString); + + fetchQualifier = [fetchSpecification qualifier]; //OK + //call fetchSpecification -isDeep + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"fetchQualifier=%@", + fetchQualifier); + + restrictingQualifier = [_entity restrictingQualifier]; //OK //nil //TODO use it !! + + //Build Where Clause + whereClauseString = [(id)fetchQualifier sqlStringForSQLExpression: self]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"whereClauseString=%@", + whereClauseString); + ASSIGN(_whereClauseString, whereClauseString); + + //Build Ordering Clause + sortOrderings = [fetchSpecification sortOrderings]; + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sortOrderings=%@", + sortOrderings); + + if ([sortOrderings count] > 0) + { + int i, count = [sortOrderings count]; + + for (i = 0; i < count; i++) + { + EOSortOrdering *order = [sortOrderings objectAtIndex: i]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"order=%@", order); + NSAssert3([order isKindOfClass: [EOSortOrdering class]], + @"order is not a EOSortOrdering but a %@: %p %@", + [order class], + order, + order); + + [self addOrderByAttributeOrdering: order]; + } + } + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"_listString=%@", _listString); + [self joinExpression]; + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"_joinClauseString=%@", + _joinClauseString); + + rootEntity=[self _rootEntityForExpression]; + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"rootEntity=%@", + [rootEntity name]); + + //Build Table List + tableList = [self tableListWithRootEntity: rootEntity]; + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"tableList=%@", tableList); + + //Build LockClause + if (lockFlag) + lockClauseString = [self lockClause]; + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"lockClauseString=%@", + lockClauseString); + + //Build UseDistinct Clause + usesDistinct = [fetchSpecification usesDistinct]; + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"usesDistinct=%d", usesDistinct); + + if (usesDistinct) + selectCommand = @"SELECT distinct "; + else + selectCommand = @"SELECT "; + + //Now Build Statement + statement = [self assembleSelectStatementWithAttributes: attributes + lock: lockFlag + qualifier: fetchQualifier + fetchOrder: sortOrderings + selectString: selectCommand + columnList: _listString + tableList: tableList + whereClause: ([_whereClauseString length] > 0 + ? _whereClauseString : nil) + joinClause: ([_joinClauseString length] > 0 + ? _joinClauseString : nil) + orderByClause: ([_orderByString length] > 0 + ? _orderByString : nil) + lockClause: lockClauseString]; + ASSIGN(_statement, statement); + + EOFLOGObjectFnStop(); +} + +- (NSString *)assembleJoinClauseWithLeftName: (NSString *)leftName + rightName: (NSString *)rightName + joinSemantic: (EOJoinSemantic)semantic +{ + NSString *op = nil; + NSString *joinClause = nil; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"join parts=%@ %d %@", + leftName, + (int)semantic, + rightName); +//call [self _sqlStringForJoinSemantic:semantic matchSemantic:2 +//[self _sqlStringForJoinSemantic:semantic matchSemantic:3 +//the 2 ret nil + + switch (semantic) + { + case EOInnerJoin: + op = @"="; + break; + case EOLeftOuterJoin: + op = @"*="; + break; + case EORightOuterJoin: + op = @"=*"; + break; + case EOFullOuterJoin: + break; + } + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"op= '%@'", op); + + if (op) + joinClause = [NSString stringWithFormat: @"%@ %@ %@", + leftName, + op, + rightName]; //TODO + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"joinClause=%@", joinClause); + + EOFLOGObjectFnStop(); + + return joinClause; +} + +- (void)addJoinClauseWithLeftName: (NSString *)leftName + rightName: (NSString *)rightName + joinSemantic: (EOJoinSemantic)semantic +{ + NSString *joinClause = nil; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"join parts=%@ %d %@", + leftName, + (int)semantic, + rightName); + + joinClause = [self assembleJoinClauseWithLeftName: leftName + rightName: rightName + joinSemantic: semantic]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"joinClause=%@", + joinClause); + if (joinClause) + { + NSMutableString *joinClauseString = [self joinClauseString]; + + if (![joinClauseString isEqualToString: @""]) + [joinClauseString appendString: @" AND "]; + + [joinClauseString appendString: joinClause]; + } + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"_joinClauseString=%@", + _joinClauseString); + + EOFLOGObjectFnStop(); +} + +/** Build join expression for all used relationships (call this) after all other query parts construction) **/ +- (void)joinExpression +{ + EOEntity *entity = nil; + NSEnumerator *relationshipEnum; + NSString *relationshipPath; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"_aliasesByRelationshipPath=%@", + _aliasesByRelationshipPath); + + // Iterate on each used relationship + relationshipEnum = [_aliasesByRelationshipPath keyEnumerator]; + while((relationshipPath = [relationshipEnum nextObject])) + { + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"relationshipPath=%@", + relationshipPath); + + // If this is not the base (root) one + if (![relationshipPath isEqualToString: @""]) + { + EOQualifier *auxiliaryQualifier = nil; + EORelationship *rel = nil; + NSArray *joins = nil; + int i, count=0; + + //Get the root entity if we haven't got it before + if (!entity) + entity=[self entity]; + + // Get the relationship for this path (non flattened by design) + rel = [entity relationshipForPath: relationshipPath]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"rel=%@", rel); + NSAssert2(rel, @"No relationship for path %@ in entity %@", + relationshipPath, + [entity name]); + + //Get the auxiliary qualifier for this relationship + auxiliaryQualifier = [rel auxiliaryQualifier]; + + if (auxiliaryQualifier) + { + NSEmitTODO(); //TODO + [self notImplemented:_cmd]; + } + + // Get relationship joins + joins = [rel joins]; + count = [joins count]; + + // Iterate on each join + for (i = 0; i < count; i++) + { + NSString *sourceRelationshipPath = nil; + NSArray *sourceRelationshipPathArray; + //Get the join + EOJoin *join=[joins objectAtIndex:i]; + // Get source and destination attributes + EOAttribute *sourceAttribute = [join sourceAttribute]; + EOAttribute *destinationAttribute = [join destinationAttribute]; + NSString *sourceAttributeAlias = nil; + NSString *destinationAttributeAlias = nil; + + // Build the source relationshipPath + sourceRelationshipPathArray = + [relationshipPath componentsSeparatedByString: @"."]; + sourceRelationshipPathArray = + [sourceRelationshipPathArray + subarrayWithRange: + NSMakeRange(0,[sourceRelationshipPathArray count] - 1)]; + sourceRelationshipPath = [sourceRelationshipPathArray + componentsJoinedByString: @"."]; + + // Get the alias for sourceAttribute + sourceAttributeAlias = [self + _aliasForRelatedAttribute: + sourceAttribute + relationshipPath: + sourceRelationshipPath]; + + // Get the alias for destinationAttribute + destinationAttributeAlias = + [self _aliasForRelatedAttribute: destinationAttribute + relationshipPath: relationshipPath]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"addJoin=%@ %d %@", + sourceAttributeAlias, + (int)[rel joinSemantic], + destinationAttributeAlias); + + // Add to join clause + [self addJoinClauseWithLeftName: sourceAttributeAlias + rightName: destinationAttributeAlias + joinSemantic: [rel joinSemantic]]; + } + } + } + + EOFLOGObjectFnStop(); +} + +- (NSString *)assembleInsertStatementWithRow: (NSDictionary *)row + tableList: (NSString *)tableList + columnList: (NSString *)columnList + valueList: (NSString *)valueList +{ + //OK + if (columnList) + return [NSString stringWithFormat: @"INSERT INTO %@ (%@) VALUES (%@)", + tableList, columnList, valueList]; + else + return [NSString stringWithFormat: @"INSERT INTO %@ VALUES (%@)", + tableList, valueList]; +} + +- (NSString *)assembleUpdateStatementWithRow: (NSDictionary *)row + qualifier: (EOQualifier *)qualifier + tableList: (NSString *)tableList + updateList: (NSString *)updateList + whereClause: (NSString *)whereClause +{ + return [NSString stringWithFormat: @"UPDATE %@ SET %@ WHERE %@", + tableList, updateList, whereClause]; +} + +- (NSString *)assembleDeleteStatementWithQualifier: (EOQualifier *)qualifier + tableList: (NSString *)tableList + whereClause: (NSString *)whereClause +{ + return [NSString stringWithFormat:@"DELETE FROM %@ WHERE %@", + tableList, whereClause]; +} + +- (NSString *)assembleSelectStatementWithAttributes: (NSArray *)attributes + lock: (BOOL)lock + qualifier: (EOQualifier *)qualifier + fetchOrder: (NSArray *)fetchOrder + selectString: (NSString *)selectString + columnList: (NSString *)columnList + tableList: (NSString *)tableList + whereClause: (NSString *)whereClause + joinClause: (NSString *)joinClause + orderByClause: (NSString *)orderByClause + lockClause: (NSString *)lockClause +{ //TODO selectString ?? + NSMutableString *sqlString; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"attributes=%@", attributes); + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"qualifier=%@", qualifier); + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"fetchOrder=%@", fetchOrder); + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"selectString=%@", selectString); + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"columnList=%@", columnList); + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"tableList=%@", tableList); + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"whereClause=%@", whereClause); + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"joinClause=%@", joinClause); + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"orderByClause=%@", orderByClause); + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"lockClause=%@", lockClause); + + sqlString = [NSMutableString stringWithFormat: @"SELECT %@ FROM %@", + columnList, tableList]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sqlString=%@", sqlString); + + if ([lockClause length] > 0) + [sqlString appendFormat: @" %@", lockClause]; + + if ([whereClause length] == 0) + whereClause = nil; + + if ([joinClause length] == 0) + joinClause = nil; + + if (whereClause && joinClause) + [sqlString appendFormat: @" WHERE %@ AND %@", + whereClause, joinClause]; + else if (whereClause || joinClause) + [sqlString appendFormat: @" WHERE %@", + (whereClause + ? whereClause + : joinClause)]; + if ([orderByClause length] > 0) + [sqlString appendFormat: @" ORDER BY %@", orderByClause]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sqlString=%@", sqlString); + EOFLOGObjectFnStop(); + + return sqlString; +} + +- (void)addSelectListAttribute: (EOAttribute *)attribute +{ + //OK + NSMutableString *listString; + NSString *string; + NSString *sqlStringForAttribute = [self sqlStringForAttribute:attribute]; + + NSAssert1(sqlStringForAttribute,@"No sqlString for attribute: %@",attribute); + + string = [[self class] formatSQLString: sqlStringForAttribute + format: [attribute readFormat]]; + listString = [self listString]; + + [self appendItem: string + toListString: listString]; +} + +- (void)addInsertListAttribute: (EOAttribute *)attribute + value: (NSString *)value +{ + //OK + NSMutableString *valueList=nil; + NSString *writeFormat=nil; + NSString *valueSQLString; + NSMutableString *listString; + NSString *attributeSQLString; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"attribute name=%@", + [attribute name]); + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"value=%@", value); + + listString = [self listString]; + + NS_DURING // debug purpose + { + attributeSQLString = [self sqlStringForAttribute: attribute]; + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"attributeSQLString=%@", + attributeSQLString); + } + NS_HANDLER + { + NSDebugMLog(@"EXCEPTION %@", localException); + [localException raise]; + } + NS_ENDHANDLER; + + NS_DURING // debug purpose + { + [self appendItem: attributeSQLString + toListString: listString]; + + valueSQLString = [self sqlStringForValue: value + attributeNamed: [attribute name]]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"valueSQLString=%@", + valueSQLString); + } + NS_HANDLER + { + NSDebugMLog(@"EXCEPTION %@", localException); + [localException raise]; + } + NS_ENDHANDLER; + + NS_DURING // debug purpose + { + writeFormat = [attribute writeFormat]; + if ([writeFormat length] > 0) + { + //TODO + } + + valueList = [self valueList]; + [self appendItem: valueSQLString + toListString: valueList]; + } + NS_HANDLER + { + NSDebugMLog(@"EXCEPTION %@", localException); + [localException raise]; + } + NS_ENDHANDLER; + + EOFLOGObjectFnStop(); +} + +- (void)addUpdateListAttribute: (EOAttribute *)attribute + value: (NSString *)value +{ + //OK + NSString *sqlStringToAdd; + NSMutableString *listString; + NSString *attributeSQLString; + NSString *valueSQLString; + NSString *writeFormat; + + EOFLOGObjectFnStart(); + + attributeSQLString = [self sqlStringForAttribute: attribute]; + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"attributeSQLString=%@", + attributeSQLString); + + valueSQLString = [self sqlStringForValue: value + attributeNamed: [attribute name]]; + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"valueSQLString=%@", + valueSQLString); + + writeFormat = [attribute writeFormat]; + + if ([writeFormat length] > 0) + { + //TODO + } + + listString = [self listString]; + sqlStringToAdd = [NSString stringWithFormat: @"%@ = %@", + attributeSQLString, + valueSQLString]; + + [self appendItem: sqlStringToAdd + toListString: listString]; + + EOFLOGObjectFnStop(); +} + ++ (NSString *)formatStringValue: (NSString *)string +{ + NSString *formatted; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @" string=%@", string); + + if (string == nil) + [NSException raise: NSInternalInconsistencyException + format: @"EOSQLExpression: Argument of formatStringValue: " + @"can't be a nil object"]; + + formatted = [NSString stringWithFormat: @"%@%@%@", @"'", string, @"'"]; + EOFLOGObjectLevelArgs(@"EOSQLExpression", @" formatted=%@", formatted); + + return formatted; +} + ++ (NSString *)formatValue: (id)value + forAttribute: (EOAttribute *)attribute +{ +//mirko new:return [value sqlString]; + NSString *formattedValue = nil; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @" value=%@ class=%@", + value, [value class]); + + NS_DURING //debug purpose + { + if (!value) + formattedValue = @"NULL"; + else + { + NSString *string; + + string = [value sqlString]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @" value %p=%@ null %p=%@", + value, value, [EONull null], [EONull null]); + + if ([value isEqual: [EONull null]]) + formattedValue = string; + else + formattedValue = [self formatSQLString: [self formatStringValue: + string] + format: [attribute readFormat]]; + } + } + NS_HANDLER + { + NSDebugMLog(@"EXCEPTION %@", localException); + [localException raise]; + } + NS_ENDHANDLER; + + EOFLOGObjectFnStop(); + + return formattedValue; +} + ++ (NSString *)formatSQLString: (NSString *)sqlString + format: (NSString *)format +{ + NSString *formatted = nil; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @" sqlString=%@ format=%@", + sqlString, format); + NSAssert1([sqlString length] > 0, @"No sqlString (%p)", sqlString); + + NS_DURING //debug purpose + { + if (!format) + formatted = sqlString; + else + { + const char *p = [format cString]; + char *s; + NSMutableString *str = [NSMutableString stringWithCapacity: + [format length]]; + + while ((s = strchr(p, '%'))) + { + switch (*(s + 1)) + { + case '%': + [str appendString: [NSString stringWithCString: p + length: s-p+1]]; + break; + case 'P': + if (s != p) + [str appendString: [NSString stringWithCString: p + length: s-p]]; + [str appendString: sqlString]; + break; + default: + if (s != p) + [str appendString: [NSString stringWithCString: p + length: s-p]]; + break; + } + + p = s + 2; + } + + if (*p) + [str appendString: [NSString stringWithCString: p]]; + + formatted = str; + } + } + NS_HANDLER + { + NSDebugMLog(@"EXCEPTION %@", localException); + [localException raise]; + } + NS_ENDHANDLER; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @" formatted=%@", formatted); + + EOFLOGObjectFnStop(); + + return formatted; +} + +//operation must have space before and after. Example: @" AND " +- (NSString*) sqlStringForArrayOfQualifiers: (NSArray*)qualifiers + operation: (NSString*)operation +{ + //OK + NSMutableString *sqlString = nil; + int i, count; + int nb=0; + + EOFLOGObjectFnStart(); + + count = [qualifiers count]; + + for (i = 0; i < count; i++) + { + EOKeyValueQualifier *kvQualifier = [qualifiers objectAtIndex: i]; + NSString *tmpSqlString = [self sqlStringForKeyValueQualifier: + kvQualifier]; + + if (tmpSqlString) + { + if (!sqlString) + sqlString = (NSMutableString*)[NSMutableString string]; + + if (nb > 0) + [sqlString appendString: operation]; + + [sqlString appendString: tmpSqlString]; + nb++; + } + } + + if (nb > 1) + { + [sqlString insertString: @"(" atIndex: 0]; + [sqlString appendString: @")"]; + } + else if (nb == 0) + sqlString = nil; + + EOFLOGObjectFnStop(); + + return sqlString; +} + +- (NSString *)sqlStringForConjoinedQualifiers: (NSArray *)qualifiers +{ + //OK + NSString *sqlString; + + EOFLOGObjectFnStart(); + + sqlString = [self sqlStringForArrayOfQualifiers: qualifiers + operation: @" AND "]; + + EOFLOGObjectFnStop(); + + return sqlString; +} + +- (NSString *)sqlStringForDisjoinedQualifiers: (NSArray *)qualifiers +{ + //OK + NSString *sqlString; + + EOFLOGObjectFnStart(); + + sqlString = [self sqlStringForArrayOfQualifiers: qualifiers + operation: @" OR "]; + + EOFLOGObjectFnStop(); + + return sqlString; +} + +- (NSString *)sqlStringForNegatedQualifier:(EOQualifier *)qualifier +{ + NSString *sqlQual; + + EOFLOGObjectFnStart(); + + sqlQual = [(id)qualifier sqlStringForSQLExpression: self]; + if (sqlQual) + sqlQual = [NSString stringWithFormat:@"not (%@)", sqlQual]; + + EOFLOGObjectFnStop(); + + return sqlQual; +} + +- (NSString *)sqlStringForKeyValueQualifier: (EOKeyValueQualifier *)qualifier +{ + //Near OK + NSString* sqlString=nil; + NSString* valueSQLString=nil; + NSString* selectorSQLString=nil; + NSString *key = nil; + id value=nil; + NSString* attributeSQLString=nil; + EOAttribute* attribute=nil; + NSString* readFormat=nil; + + EOFLOGObjectFnStart(); + + key = [qualifier key];//OK + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"key=%@", key); + + value = [qualifier value];//OK + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"value=%@", value); + + attributeSQLString = [self sqlStringForAttributeNamed: key];//OK + + NSAssert1(attributeSQLString, @"No sqlStringForAttributeNamed:%@", key); + EOFLOGObjectLevelArgs(@"EOSQLExpression",@"attributeSQLString=%@", + attributeSQLString); + + attribute = [_entity attributeForPath: key]; + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"attribute=%@", attribute); + + readFormat = [attribute readFormat]; + + if (readFormat) + { + NSEmitTODO(); //TODO + } + + valueSQLString = [self sqlStringForValue: value + attributeNamed: key];//OK + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"valueSQLString=%@", + valueSQLString); + selectorSQLString = [self sqlStringForSelector: [qualifier selector] + value: value];//OK //value ?? + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"selectorSQLString=%@", + selectorSQLString); + + //?? + if (sel_eq([qualifier selector], EOQualifierOperatorLike)) + valueSQLString = [[self class] sqlPatternFromShellPattern: valueSQLString]; + else if (sel_eq([qualifier selector], EOQualifierOperatorCaseInsensitiveLike)) + { + valueSQLString = [[self class] sqlPatternFromShellPattern: valueSQLString]; + //VERIFY + attributeSQLString = [NSString stringWithFormat: @"UPPER(%@)", + attributeSQLString]; + valueSQLString = [NSString stringWithFormat: @"UPPER(%@)", + valueSQLString]; + } + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"attributeSQLString=%@", + attributeSQLString); + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"selectorSQLString=%@", + selectorSQLString); + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"valueSQLString=%@", + valueSQLString); + + sqlString = [NSString stringWithFormat: @"%@ %@ %@", + attributeSQLString, + selectorSQLString, + valueSQLString]; + /* + NSString* sqlString = [NSString stringWithFormat: @"%@ %@ %@", + [[self class] formatSQLString: + [self sqlStringForAttributeNamed:key] + format: + [[_entity attributeNamed:key] + readFormat]], + selString, + valueString]; +*/ + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sqlString=%@", sqlString); + EOFLOGObjectFnStop(); + + return sqlString; //return someting like t1.label = 'XXX' +} + +- (NSString *)sqlStringForKeyComparisonQualifier: (EOKeyComparisonQualifier *)qualifier +{ + return [NSString stringWithFormat:@"%@ %@ %@", + [[self class] formatSQLString: + [self sqlStringForAttributeNamed: + [qualifier leftKey]] + format: + [[_entity attributeNamed: + [qualifier leftKey]] + readFormat]], + [self sqlStringForSelector:[qualifier selector] value:nil], + [[self class] formatSQLString: + [self sqlStringForAttributeNamed: + [qualifier rightKey]] + format:[[_entity attributeNamed: + [qualifier rightKey]] + readFormat]]]; +} + +- (NSString *)sqlStringForValue:(NSString *)valueString + caseInsensitiveLikeKey:(NSString *)keyString +{ + [self notImplemented:_cmd]; //TODO + return nil; +} + +- (void)addOrderByAttributeOrdering:(EOSortOrdering *)sortOrdering +{ + SEL orderSelector = NULL; + NSString *orderStringFormat = nil; + NSString *keyString = nil; + id key = nil; + + orderSelector = [sortOrdering selector]; + + if (sel_eq(orderSelector, EOCompareAscending)) + orderStringFormat = @"(%@) asc"; + else if (sel_eq(orderSelector, EOCompareDescending)) + orderStringFormat = @"(%@) desc"; + else if (sel_eq(orderSelector, EOCompareCaseInsensitiveAscending)) + orderStringFormat = @"upper(%@) asc"; + else if (sel_eq(orderSelector, EOCompareCaseInsensitiveDescending)) + orderStringFormat = @"upper(%@) desc"; + + key = [sortOrdering key]; + + NSAssert1(key, + @"Key in sort ordering", + sortOrdering); + + keyString = [self sqlStringForAttributeNamed: key];//TODO VERIFY + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"keyString=%@", keyString); + + NSAssert1(keyString, + @"No sql string for key named \"%@\"", + key); + + [self appendItem: [NSString stringWithFormat: orderStringFormat, + keyString] + toListString: [self orderByString]]; +} + ++ (BOOL)useQuotedExternalNames +{ + return [[NSUserDefaults standardUserDefaults] + boolForKey: @"EOAdaptorQuotesExternalNames"]; +} + ++ (void)setUseQuotedExternalNames:(BOOL)flag +{ + NSString *yn = (flag ? @"YES" : @"NO"); + + [[NSUserDefaults standardUserDefaults] + setObject: yn forKey: @"EOAdaptorQuotesExternalNames"]; +} + +- (NSString *)externalNameQuoteCharacter +{ + if ([[self class] useQuotedExternalNames]) + return @"\""; + + return @""; +} + +- (void)setUseAliases: (BOOL)useAliases +{ + _useAliases = useAliases; +} + +- (BOOL)useAliases +{ + return _useAliases; +} + +- (NSString *)sqlStringForSchemaObjectName: (NSString *)name +{ + //OK + NSString *quote = [self externalNameQuoteCharacter]; + + return [NSString stringWithFormat:@"%@%@%@", quote, name, quote]; +} + +- (NSString *)sqlStringForAttributeNamed: (NSString *)name +{ + //OK + EOAttribute *attribute = nil; + NSString *sqlString = nil; + NSArray *keyParts; + NSString *key = nil; + EOEntity *entity=_entity; + NSMutableArray *attributePath = nil; + int i, count; + + EOFLOGObjectFnStart(); + + NSAssert(entity,@"no entity"); + NSAssert(name,@"no attribute name"); + NSAssert([name length]>0,@"attribute name is empty"); + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"name=%@", name); + + keyParts = [name componentsSeparatedByString:@"."]; + count = [keyParts count]; + + for (i = 0; i < count - 1; i++) + { + EORelationship *rel; + + key = [keyParts objectAtIndex: i]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"keyPart=%@", key); + + rel = [entity anyRelationshipNamed: key]; + + NSAssert2(rel, + @"no relationship named %@ in entity %@", + key, + [entity name]); + + if (attributePath) + [attributePath addObject: rel]; + else + attributePath = [NSMutableArray arrayWithObject: rel]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"rel=%@", rel); + + entity = [rel destinationEntity]; + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"entity name=%@", + [entity name]); + } + + key = [keyParts lastObject]; + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"key=%@", key); + + attribute = [entity anyAttributeNamed: key]; + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"attribute=%@", attribute); + + NSAssert4(attribute, + @"no attribute named %@ in entity %@\nAttributesByName=%@\nattributes=%@", + key, + [entity name], + [entity attributesByName], + [entity attributes]); + + if (attributePath) + { + [attributePath addObject: attribute]; + sqlString = [self sqlStringForAttributePath: attributePath]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sqlString=%@", sqlString); + NSAssert1(sqlString, + @"no sql string for attribute path %@", + attributePath); + NSAssert1([sqlString length], + @"empty sql string for attribute path %@", + attributePath); + } + else + { + sqlString = [self sqlStringForAttribute: attribute]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sqlString=%@", sqlString); + NSAssert1(sqlString, + @"no sql string for attribute %@", + attribute); + NSAssert1([sqlString length], + @"empty sql string for attribute %@", + attribute); + } + + EOFLOGObjectFnStop(); + + return sqlString; +} + +- (NSString *)sqlStringForSelector: (SEL)selector + value: (id)value +{ + //seems OK + if (sel_eq(selector, EOQualifierOperatorEqual)) + { + if ([value isKindOfClass: [[EONull null] class]]) + return @"is"; + else + return @"="; + } + else if (sel_eq(selector, EOQualifierOperatorNotEqual)) + { + if ([value isKindOfClass: [[EONull null] class]]) + return @"is not"; + else + return @"<>"; + } + else if (sel_eq(selector, EOQualifierOperatorLessThan)) + return @"<"; + else if (sel_eq(selector, EOQualifierOperatorGreaterThan)) + return @">"; + else if (sel_eq(selector, EOQualifierOperatorLessThanOrEqualTo)) + return @"<="; + else if (sel_eq(selector, EOQualifierOperatorGreaterThanOrEqualTo)) + return @">="; + else if (sel_eq(selector, EOQualifierOperatorLike)) + return @"like"; + else if (sel_eq(selector, EOQualifierOperatorCaseInsensitiveLike)) + return @"like"; //same as sensitive +/* //TODO else if(sel_eq(selector, EOQualifierOperatorContains)) + return @"like";*/ + else + { + [NSException raise: NSInternalInconsistencyException + format: @"EOSQLExpression: Unknown selector of sqlStringForSelector:value:"]; + } + + return nil; +} + +- (NSString *)sqlStringForValue: (id)value + attributeNamed: (NSString*)attributeName +{ + EOAttribute *attribute; + NSString *sqlString = nil; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"value=%@", value); + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"attributeName=%@", + attributeName); + + attribute = [_entity attributeForPath: attributeName]; + + NSAssert2(attribute, + @"No attribute for path \"%@\" in entity \"%@\"", + attributeName, + [_entity name]); + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"attribute=%@", attribute); + + if ([self shouldUseBindVariableForAttribute: attribute] + || [self mustUseBindVariableForAttribute: attribute]) + { + //TODO verify + NSDictionary *binding; + + binding = [self bindVariableDictionaryForAttribute: attribute + value: value]; + [_bindings addObject: binding]; + + sqlString = [binding objectForKey: EOBindVariablePlaceHolderKey]; + } + else + { + //attr externalType + EOFLOGObjectLevelArgs(@"EOSQLExpression", @" value=%@ class=%@", + value, [value class]); + EOFLOGObjectLevelArgs(@"EOSQLExpression", @" self %@ class=%@", + self, [self class]); + //call attribute entity + //call entity model + + sqlString = [[self class] formatValue: value + forAttribute: attribute]; //?? + EOFLOGObjectLevelArgs(@"EOSQLExpression", @" sqlString=%@", sqlString); + + NSAssert4([sqlString length] > 0, + @"No sqlString (%p) for value '%@' (class %@) for Attribute '%@'", + sqlString, value, [value class], attribute); + + //??? Mirko: + sqlString = [[self class] formatSQLString: sqlString + format: [attribute readFormat]]; + } + + EOFLOGObjectFnStop(); + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sqlString=%@", sqlString); + + return sqlString; +} + +- (NSString *)sqlStringForAttribute: (EOAttribute *)anAttribute +{ + NSString *sqlString = nil; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"anAttribute=%@\nisFlattened=%s\n_definitionArray=%@\n_definitionArray count=%d", + anAttribute, + ([anAttribute isFlattened] ? "YES" : "NO"), + [anAttribute _definitionArray], + [[anAttribute _definitionArray]count]); + + if ([anAttribute isFlattened]) + { + sqlString = [self sqlStringForAttributePath: + [anAttribute _definitionArray]]; + + NSAssert1(sqlString, @"No sqlString for flattened attribute: %@", + anAttribute); + } +//mirko: +/* +else if([anAttribute isDerived] == YES) + return [anAttribute definition]; +*/ + else + { + if (![self useAliases])//OK + { + sqlString = [anAttribute columnName]; + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sqlString=%@", sqlString); + } + else + { + //TODO VERIFY en select: return t0.abbrev + NSEnumerator *relationshipEnum; + NSEnumerator *defEnum = nil; + NSArray *defArray, *attrArray = nil; + NSString *relationshipPath; + NSString *relationshipString = nil; + EOEntity *currentEntity = nil; + + relationshipEnum = [_aliasesByRelationshipPath keyEnumerator]; + while ((relationshipPath = [relationshipEnum nextObject])) + { + currentEntity = _entity; + EOFLOGObjectLevelArgs(@"EOSQLExpression",@"relationshipPath=%@",relationshipPath); + + if (![relationshipPath isEqualToString: @""]) + { + defArray = [relationshipPath componentsSeparatedByString: + @"."]; + defEnum = [defArray objectEnumerator]; + + while ((relationshipString = [defEnum nextObject])) + { + EOFLOGObjectLevelArgs(@"EOSQLExpression", + @"relationshipString=%@", + relationshipString); + + currentEntity = [[currentEntity + relationshipNamed: relationshipString] + destinationEntity]; + } // TODO entity + } + + attrArray = [currentEntity attributes]; + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"attrArray=%@", + attrArray); + + if (attrArray) + { + if ([attrArray containsObject: anAttribute]) + { + NSString *columnName = [anAttribute columnName]; + + if (!columnName) + { + NSEmitTODO(); //TODO what to do when there's no column name (definition only like "((firstName || ' ') || lastName)") ? + + EOFLOGObjectLevelArgs(@"EOSQLExpression", + @"anAttribute=%@", + anAttribute); + EOFLOGObjectLevelArgs(@"EOSQLExpression", + @"columnName=%@", columnName); + EOFLOGObjectLevelArgs(@"EOSQLExpression", + @"attrArray=%@", attrArray); + EOFLOGObjectLevelArgs(@"EOSQLExpression", + @"relationshipPath=%@", + relationshipPath); + } + + NSAssert1(columnName, @"No columnName for attribute %@", + anAttribute); + + sqlString = [NSString stringWithFormat: @"%@.%@", + [_aliasesByRelationshipPath + objectForKey: relationshipPath], + columnName]; + EOFLOGObjectLevelArgs(@"EOSQLExpression", + @"sqlString=%@", sqlString); + } + } + } + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sqlString=%@", + sqlString); + } + + NSAssert1(sqlString, @"No SQLString for attribute %@", anAttribute); + } + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sqlString=%@", sqlString); + EOFLOGObjectFnStop(); + + return sqlString; +} + +- (NSString *)sqlStringForAttributePath: (NSArray *)path +{ + NSString *sqlString = nil; + + if (!_useAliases) + { + sqlString = [(EOAttribute *)[path lastObject] columnName]; + + NSAssert2(sqlString, + @"No sqlString for path: %@ (lastObject=%@) (!_useAliases)", + path, + [path lastObject]); + } + else + { + NSMutableString *relationshipPathString = [NSMutableString string]; + int i, count = [path count]; + + if (count > 1) + { + for (i = 0; i < (count - 1); i++) + { + if (i > 0) + [relationshipPathString appendString: @"."]; + + [relationshipPathString + appendString: [(EORelationship *)[path objectAtIndex:i] + name]]; + } + + //TODO + //call attribute _definitionArray + sqlString = [self _aliasForRelatedAttribute: [path lastObject] + relationshipPath: relationshipPathString]; + + NSAssert2(sqlString, + @"No sqlString for path: %@ (lastObject=%@) (_useAliases)", + path, + [path lastObject]); + } + } + + return sqlString; +} + +- (void)appendItem: (NSString *)itemString + toListString: (NSMutableString *)listString +{ + //OK + NSAssert1(listString,@"No list string when appending %@",itemString); + + if (listString) + { +#if 0 + str = [listString cString]; + while (*str) + { + if (!isspace(*str++)) + [listString appendString: @", "]; + } +#endif + + if ([listString length]) + [listString appendString: @", "]; + + [listString appendString: itemString]; + } +} + ++ (NSString *)sqlPatternFromShellPattern: (NSString *)pattern +{ + const char *s, *p, *init = [pattern cString]; + NSMutableString *str = [NSMutableString stringWithCapacity: + [pattern length]]; + + for (s = p = init; *s; s++) + { + switch (*s) + { + case '*': + if (s != p) + [str appendString: [NSString stringWithCString: p + length: s-p]]; + [str appendString: @"%"]; + p = s+1; + break; + case '?': + if (s != p) + [str appendString:[NSString stringWithCString: p + length: s-p]]; + [str appendString: @"_"]; + p = s+1; + break; + case '%': + if (s != p) + [str appendString:[NSString stringWithCString: p + length: s-p]]; + + if (s != init && *(s-1) == '[' && *(s+1) == ']') + { + [str appendString: @"%]"]; + p = s+2; s++; + } + else + { + [str appendString: @"[%]"]; + p = s+1; + } + break; + case '_': + if (s != p) + [str appendString:[NSString stringWithCString: p + length: s-p]]; + + if (s != init && *(s-1) == '[' && *(s+1) == ']') + { + [str appendString: @"_]"]; + p = s+2; p++; + } + else + { + [str appendString: @"[_]"]; + p = s+1; + } + break; + } + } + + if (*p) + [str appendString: [NSString stringWithCString: p]]; + + return str; +} + ++ (NSString *)sqlPatternFromShellPattern: (NSString *)pattern + withEscapeCharacter: (unichar)escapeCharacter +{ + const char *s, *p, *init = [pattern cString]; + NSMutableString *str = [NSMutableString stringWithCapacity: + [pattern length]]; + + for (s = p = init; *s; s++) + { + switch (*s) + { + case '*': + if (s != p) + [str appendString: [NSString stringWithCString: p + length: s-p]]; + [str appendString: @"%"]; + p = s+1; + break; + case '?': + if (s != p) + [str appendString: [NSString stringWithCString: p + length: s-p]]; + [str appendString: @"_"]; + p = s+1; + break; + case '%': + if (s != p) + [str appendString:[NSString stringWithCString: p + length: s-p]]; + + if (s != init && *(s-1) == '[' && *(s+1) == ']') + { + [str appendString: @"%]"]; + p = s+2; s++; + } + else + { + [str appendString: @"[%]"]; + p = s+1; + } + break; + case '_': + if (s != p) + [str appendString:[NSString stringWithCString: p + length: s-p]]; + + if (s != init && *(s-1) == '[' && *(s+1) == ']') + { + [str appendString: @"_]"]; + p = s+2; p++; + } + else + { + [str appendString: @"[_]"]; + p = s+1; + } + break; + } + } + + if (*p) + [str appendString:[NSString stringWithCString:p]]; + + return str; +} + +- (NSMutableDictionary *)bindVariableDictionaryForAttribute: (EOAttribute *)attribute + value: value +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +- (BOOL)shouldUseBindVariableForAttribute: (EOAttribute *)att +{ + return NO; +} + +- (BOOL)mustUseBindVariableForAttribute: (EOAttribute *)att +{ + return NO; +} + ++ (BOOL)useBindVariables +{ + return [[NSUserDefaults standardUserDefaults] + boolForKey: @"EOAdaptorUseBindVariables"]; +} + ++ (void)setUseBindVariables:(BOOL)flag +{ + NSString *yn = (flag ? @"YES" : @"NO"); + + [[NSUserDefaults standardUserDefaults] + setObject:yn forKey:@"EOAdaptorUseBindVariables"]; +} + +- (NSArray *)bindVariableDictionaries +{ + return _bindings; +} + +- (void)addBindVariableDictionary:(NSMutableDictionary *)binding +{ + [_bindings addObject:binding]; +} + +@end /* EOSQLExpression */ + + +@implementation EOSQLExpression (EOSQLExpressionPrivate) +- (EOEntity*)_rootEntityForExpression +{ + //return [self notImplemented:_cmd]; //TODO + return _entity; +}; + +/** Return the alias (t0,t1,...) for the relationshipPath +This add a new alias if there not already one +This also add alias for all relationships used by relationshipPath (so joinExpression can build join expressions for really all used relationships) +All relationshipPaths in _aliasesByRelationshipPath are direct paths **/ +- (NSString*) _aliasForRelationshipPath:(NSString*)relationshipPath//toLanguage +{ + //OK ? + NSString *flattenRelPath; + NSMutableString *mutableFlattenRelPath; + NSString *alias = nil; + NSMutableArray *pathElements; + int count; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"relationshipPath=%@", + relationshipPath); + NSAssert(relationshipPath, @"No relationshipPath"); + + if ([relationshipPath length] == 0) // "" relationshipPath is handled by _aliasesByRelationshipPath lookup + flattenRelPath = relationshipPath; + else + // Find real path + flattenRelPath = [self _flattenRelPath: relationshipPath + entity: _entity]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"flattenRelPath=\"%@\"", + flattenRelPath); + + mutableFlattenRelPath = [[flattenRelPath mutableCopy] autorelease]; + pathElements = [[[mutableFlattenRelPath componentsSeparatedByString: @"."] + mutableCopy] autorelease]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"pathElements=%@", pathElements); + + count = [pathElements count]; + + while (count > 0) + { + NSString *tmpAlias; + + EOFLOGObjectLevelArgs(@"EOSQLExpression",@"count=%d flattenRelPath=%@", + count, + mutableFlattenRelPath); + + tmpAlias = [_aliasesByRelationshipPath objectForKey: + mutableFlattenRelPath]; + + if (!tmpAlias) + { + tmpAlias = [NSString stringWithFormat: @"t%d", _alias++]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"add alias %@ for %@", + tmpAlias, mutableFlattenRelPath); + + [_aliasesByRelationshipPath setObject: tmpAlias + forKey: [[mutableFlattenRelPath copy] + autorelease]]; //immuable key ! + } + + if (!alias) + alias = tmpAlias; + if (count > 0) + { + NSString *part = [pathElements lastObject]; + + if (count > 1 || [part length] > 0) //we may have only "" as original path + [mutableFlattenRelPath deleteSuffix: part]; + + if (count > 1) + [mutableFlattenRelPath deleteSuffix: @"."]; + + [pathElements removeLastObject]; + } + + count--; + } + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"alias=%@", alias); + EOFLOGObjectFnStop(); + + return alias; +} + +- (NSString*) _flattenRelPath: (NSString*)relationshipPath + entity: (EOEntity*)entity + +{ + // near OK + NSMutableString *flattenRelPath = [NSMutableString string]; + EORelationship *relationship = nil; + NSArray *pathElements = nil; + int i, count; + + EOFLOGObjectFnStart(); + + NSAssert(relationshipPath, @"No relationshipPath"); + NSAssert([relationshipPath length] > 0, @"Empty relationshipPath"); + + pathElements = [relationshipPath componentsSeparatedByString: @"."]; + count = [pathElements count]; + + for (i = 0; i < count; i++) + { + NSString *relPath = nil; + NSString *part = [pathElements objectAtIndex: i]; + + relationship = [entity anyRelationshipNamed: part]; + + NSAssert2(relationship, + @"no relationship named %@ in entity %@", + part, + [entity name]); + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"i=%d part=%@ rel=%@", + i, part, relationship); + + if ([relationship isFlattened]) + { + NSString *definition = [relationship definition]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", + @"definition=%@ relationship=%@", + definition, + relationship); + + relPath = [self _flattenRelPath: definition + entity: entity]; + } + else + relPath = [relationship name]; + + if (i > 0) + [flattenRelPath appendString: @"."]; + + [flattenRelPath appendString: relPath]; + + entity = [relationship destinationEntity]; + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"entity name=%@", + [entity name]); + } + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"flattenRelPath=%@", + flattenRelPath); + EOFLOGObjectFnStop(); + + return flattenRelPath; +} + +- (NSString*) _sqlStringForJoinSemantic: (EOJoinSemantic)joinSemantic + matchSemantic: (int)param1 +{ + return [self notImplemented: _cmd]; //TODO +} + +- (NSString*) _aliasForRelatedAttribute: (EOAttribute*)attribute + relationshipPath: (NSString*)relationshipPath + +{ + NSString *alias; + NSString *relPathAlias; + NSString *attributeColumnName; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"attribute=%@", attribute); + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"relationshipPath=%@", + relationshipPath); + + relPathAlias = [self _aliasForRelationshipPath: relationshipPath]; //ret "t1" + attributeColumnName = [attribute columnName]; // ret "label" + attributeColumnName = [self sqlStringForSchemaObjectName: + attributeColumnName]; // ret quoted columnName + + alias = [NSString stringWithFormat: @"%@.%@", + relPathAlias, + attributeColumnName]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"alias=%@", alias); + EOFLOGObjectFnStop(); + + return alias;//Like t1.label +} + +- (id) _entityForRelationshipPath: (id)param0 + origin: (id)param1 +{ + return [self notImplemented: _cmd]; //TODO +} + +@end + +@implementation NSString (EOSQLFormatting) + +- (NSString *)sqlString +{ + return self; +} + +@end + + +@implementation NSNumber (EOSQLFormatting) + +- (NSString *)sqlString +{ + return [self stringValue]; +} + + +@implementation NSObject (EOSQLFormatting) + +- (NSString *)sqlString +{ + return [self description]; +} + +@end + + +NSString *EOCreateTablesKey = @"EOCreateTablesKey"; +NSString *EODropTablesKey = @"EODropTablesKey"; +NSString *EOCreatePrimaryKeySupportKey = @"EOCreatePrimaryKeySupportKey"; +NSString *EODropPrimaryKeySupportKey = @"EODropPrimaryKeySupportKey"; +NSString *EOPrimaryKeyContraintsKey = @"EOPrimaryKeyContraintsKey"; +NSString *EOForeignKeyConstraintsKey = @"EOForeignKeyConstraintsKey"; +NSString *EOCreateDatabaseKey = @"EOCreateDatabaseKey"; +NSString *EODropDatabaseKey = @"EODropDatabaseKey"; + + +@implementation EOSQLExpression (EOSchemaGeneration) + ++ (NSArray *)foreignKeyConstraintStatementsForRelationship: (EORelationship *)relationship +{ + NSMutableArray *array, *sourceColumns, *destColumns; + EOSQLExpression *sqlExpression; + NSEnumerator *joinEnum; + EOJoin *join; + int num; + + EOFLOGClassFnStartOrCond(@"EOSQLExpression"); + + array = [NSMutableArray arrayWithCapacity: 1]; + + if ([[relationship entity] model] + != [[relationship destinationEntity] model]) + { + EOFLOGClassFnStopOrCond(@"EOSQLExpression"); + + return array; + } + + if ([relationship isToMany] == YES + || [[relationship inverseRelationship] isToMany] == NO) + { + EOFLOGClassFnStopOrCond(@"EOSQLExpression"); + + return array; + } + + sqlExpression = [self sqlExpressionWithEntity: [relationship entity]]; + + num = [[relationship joins] count]; + + sourceColumns = [NSMutableArray arrayWithCapacity: num]; + destColumns = [NSMutableArray arrayWithCapacity: num]; + + joinEnum = [[relationship joins] objectEnumerator]; + while ((join = [joinEnum nextObject])) + { + [sourceColumns addObject: [join sourceAttribute]]; + [destColumns addObject: [join destinationAttribute]]; + } + + [sqlExpression prepareConstraintStatementForRelationship: relationship + sourceColumns: sourceColumns + destinationColumns: destColumns]; + + [array addObject: sqlExpression]; + + EOFLOGClassFnStopOrCond(@"EOSQLExpression"); + + return array; +} + +// default implementation verifies that relationship joins on foreign key +// of destination and calls +// prepareConstraintStatementForRelationship:sourceColumns:destinationColumns: + ++ (NSArray *)createTableStatementsForEntityGroup: (NSArray *)entityGroup +{ + EOSQLExpression *sqlExp; + NSEnumerator *entityEnum, *attrEnum; + EOAttribute *attr; + EOEntity *entity; + + EOFLOGClassFnStartOrCond(@"EOSQLExpression"); + + sqlExp = [self sqlExpressionWithEntity:[entityGroup objectAtIndex: 0]]; + + entityEnum = [entityGroup objectEnumerator]; + while ((entity = [entityEnum nextObject])) + { + attrEnum = [[entity attributes] objectEnumerator]; + + while ((attr = [attrEnum nextObject])) + [sqlExp addCreateClauseForAttribute: attr]; + } + + [sqlExp setStatement: [NSString stringWithFormat:@"CREATE TABLE %@ (%@)", + [[entityGroup objectAtIndex: 0] externalName], + [self listString]]]; + + EOFLOGClassFnStopOrCond(@"EOSQLExpression"); + + return [NSArray arrayWithObject: sqlExp]; +} + ++ (NSArray *)dropTableStatementsForEntityGroup:(NSArray *)entityGroup +{ + NSArray *newArray = nil; + + EOFLOGClassFnStartOrCond(@"EOSQLExpression"); + + newArray = [NSArray arrayWithObject: + [self expressionForString: + [NSString stringWithFormat: @"DROP TABLE %@", + [[entityGroup objectAtIndex: 0] + externalName]]]]; + + EOFLOGClassFnStopOrCond(@"EOSQLExpression"); + + return newArray; +} + ++ (NSArray *)primaryKeyConstraintStatementsForEntityGroup:(NSArray *)entityGroup +{ + EOSQLExpression *sqlExp; + NSMutableString *listString; + NSEnumerator *attrEnum; + EOAttribute *attr; + EOEntity *entity; + BOOL first = YES; + + EOFLOGClassFnStartOrCond(@"EOSQLExpression"); + + entity = [entityGroup objectAtIndex: 0]; + listString = [NSMutableString stringWithCapacity: 30]; + + attrEnum = [[entity primaryKeyAttributes] objectEnumerator]; + while ((attr = [attrEnum nextObject])) + { + NSString *columnName = [attr columnName]; + + if (!columnName || ![columnName length]) + continue; + + if (first == NO) + [listString appendString: @", "]; + + [listString appendString: columnName]; + first = NO; + } + + if (first == YES) + { + EOFLOGClassFnStopOrCond(@"EOSQLExpression"); + + return [NSArray array]; + } + + sqlExp = [self sqlExpressionWithEntity:[entityGroup objectAtIndex: 0]]; + + [sqlExp setStatement: [NSString stringWithFormat: + @"ALTER TABLE %@ ADD PRIMARY KEY (%@)", + [entity externalName], + listString]]; + + EOFLOGClassFnStopOrCond(@"EOSQLExpression"); + + return [NSArray arrayWithObject: sqlExp]; +} + ++ (NSArray *)primaryKeySupportStatementsForEntityGroup: (NSArray *)entityGroup +{ + NSArray *newArray = nil; + NSString *seqName = nil; + + EOFLOGClassFnStartOrCond(@"EOSQLExpression"); + + seqName = [NSString stringWithFormat: @"%@_SEQ", + [[entityGroup objectAtIndex: 0] + primaryKeyRootName]]; + + newArray = [NSArray arrayWithObject: + [self expressionForString: + [NSString stringWithFormat: @"CREATE SEQUENCE %@", + seqName]]]; + + EOFLOGClassFnStopOrCond(@"EOSQLExpression"); + + return newArray; +} + ++ (NSArray *)dropPrimaryKeySupportStatementsForEntityGroup: (NSArray *)entityGroup +{ + NSArray *newArray = nil; + NSString *seqName = nil; + + EOFLOGClassFnStartOrCond(@"EOSQLExpression"); + + seqName = [NSString stringWithFormat: @"%@_SEQ", + [[entityGroup objectAtIndex: 0] + primaryKeyRootName]]; + + newArray = [NSArray arrayWithObject: + [self expressionForString: + [NSString stringWithFormat: @"DROP SEQUENCE %@", + seqName]]]; + + EOFLOGClassFnStopOrCond(@"EOSQLExpression"); + + return newArray; +} + ++ (NSArray *)createTableStatementsForEntityGroups: (NSArray *)entityGroups +{ + NSMutableArray *array; + NSEnumerator *groupsEnum; + NSArray *group; + + EOFLOGClassFnStartOrCond(@"EOSQLExpression"); + + array = [NSMutableArray arrayWithCapacity: [entityGroups count]]; + + groupsEnum = [entityGroups objectEnumerator]; + while ((group = [groupsEnum nextObject])) + { + [array addObjectsFromArray: + [self createTableStatementsForEntityGroup: group]]; + } + + EOFLOGClassFnStopOrCond(@"EOSQLExpression"); + + return array; +} + ++ (NSArray *)dropTableStatementsForEntityGroups: (NSArray *)entityGroups +{ + NSMutableArray *array; + NSEnumerator *groupsEnum; + NSArray *group; + + EOFLOGClassFnStartOrCond(@"EOSQLExpression"); + + array = [NSMutableArray arrayWithCapacity: [entityGroups count]]; + + groupsEnum = [entityGroups objectEnumerator]; + while ((group = [groupsEnum nextObject])) + { + [array addObjectsFromArray: + [self dropTableStatementsForEntityGroup: group]]; + } + + EOFLOGClassFnStopOrCond(@"EOSQLExpression"); + + return array; +} + ++ (NSArray *)primaryKeyConstraintStatementsForEntityGroups: (NSArray *)entityGroups +{ + NSMutableArray *array; + NSEnumerator *groupsEnum; + NSArray *group; + + EOFLOGClassFnStartOrCond(@"EOSQLExpression"); + + array = [NSMutableArray arrayWithCapacity: [entityGroups count]]; + + groupsEnum = [entityGroups objectEnumerator]; + while ((group = [groupsEnum nextObject])) + { + [array addObjectsFromArray: + [self primaryKeyConstraintStatementsForEntityGroup: group]]; + } + + EOFLOGClassFnStopOrCond(@"EOSQLExpression"); + + return array; +} + ++ (NSArray *)primaryKeySupportStatementsForEntityGroups: (NSArray *)entityGroups +{ + NSMutableArray *array; + NSEnumerator *groupsEnum; + NSArray *group; + + EOFLOGClassFnStartOrCond(@"EOSQLExpression"); + + array = [NSMutableArray arrayWithCapacity: [entityGroups count]]; + + groupsEnum = [entityGroups objectEnumerator]; + while ((group = [groupsEnum nextObject])) + { + [array addObjectsFromArray: + [self primaryKeySupportStatementsForEntityGroup: group]]; + } + + EOFLOGClassFnStopOrCond(@"EOSQLExpression"); + + return array; +} + ++ (NSArray *)dropPrimaryKeySupportStatementsForEntityGroups: (NSArray *)entityGroups +{ + NSMutableArray *array; + NSEnumerator *groupsEnum; + NSArray *group; + + EOFLOGClassFnStartOrCond(@"EOSQLExpression"); + + array = [NSMutableArray arrayWithCapacity: [entityGroups count]]; + + groupsEnum = [entityGroups objectEnumerator]; + while ((group = [groupsEnum nextObject])) + { + [array addObjectsFromArray: + [self dropPrimaryKeySupportStatementsForEntityGroup: group]]; + } + + EOFLOGClassFnStopOrCond(@"EOSQLExpression"); + + return array; +} + ++ (void)appendExpression: (EOSQLExpression *)expression + toScript: (NSMutableString *)script +{ + EOFLOGClassFnStartOrCond(@"EOSQLExpression"); + + [script appendFormat:@"%@;\n", [expression statement]]; + + EOFLOGClassFnStopOrCond(@"EOSQLExpression"); +} + + ++ (NSString *)schemaCreationScriptForEntities: (NSArray *)entities + options: (NSDictionary *)options +{ + NSMutableString *script = [NSMutableString stringWithCapacity:50]; + NSEnumerator *arrayEnum; + EOSQLExpression *sqlExp; + + EOFLOGClassFnStartOrCond(@"EOSQLExpression"); + + arrayEnum = [[self schemaCreationStatementsForEntities: entities + options: options] objectEnumerator]; + + while ((sqlExp = [arrayEnum nextObject])) + [self appendExpression: sqlExp toScript: script]; + + EOFLOGClassFnStopOrCond(@"EOSQLExpression"); + + return script; +} + +struct _schema +{ + NSString *key; + NSString *value; + SEL selector; +}; + ++ (NSArray *)schemaCreationStatementsForEntities: (NSArray *)entities + options: (NSDictionary *)options +{ + NSMutableArray *array = [NSMutableArray arrayWithCapacity: 5]; + NSMutableArray *groups = [NSMutableArray arrayWithCapacity: 5]; + NSMutableArray *group; + NSString *externalName; + EOEntity *entity; + int i, h, count; + struct _schema defaults[] = { + {EOCreateTablesKey , @"YES", + @selector(createTableStatementsForEntityGroups:)}, + {EODropTablesKey , @"YES", + @selector(dropTableStatementsForEntityGroups:)}, + {EOCreatePrimaryKeySupportKey, @"YES", + @selector(primaryKeySupportStatementsForEntityGroups:)}, + {EODropPrimaryKeySupportKey , @"YES", + @selector(dropPrimaryKeySupportStatementsForEntityGroups:)}, + {EOPrimaryKeyContraintsKey , @"YES", + @selector(primaryKeyConstraintStatementsForEntityGroups:)}, + {EOForeignKeyConstraintsKey , @"NO", + @selector(foreignKeyConstraintStatementsForRelationship:)}, + {nil, nil}, + }; + + EOFLOGClassFnStartOrCond(@"EOSQLExpression"); + + count = [entities count]; + + for (i = 0; i < count; i++) + { + entity = [entities objectAtIndex: i]; + externalName = [entity externalName]; + + group = [NSMutableArray arrayWithCapacity: 1]; + [groups addObject: group]; + [group addObject: entity]; + + for (h = i + 1; h < count; h++) + { + if ([[[entities objectAtIndex: h] externalName] + isEqual: externalName]) + [group addObject: [entities objectAtIndex: h]]; + } + } + + for (i = 0; defaults[i].key != nil; i++) + { + NSString *value; + + value = [options objectForKey: defaults[i].key]; + + if (!value) + value = defaults[i].value; + + if ([value isEqual: @"YES"] == YES) + { + [array addObjectsFromArray: + [self performSelector: defaults[i].selector + withObject: groups]]; + } + } + + EOFLOGClassFnStopOrCond(@"EOSQLExpression"); + + return array; +} + +- (NSString *)columnTypeStringForAttribute:(EOAttribute *)attribute +{ + NSString *extType = [attribute externalType]; + int precision = [attribute precision]; + int scale = [attribute scale]; + + EOFLOGClassFnStartOrCond(@"EOSQLExpression"); + + if (precision) + { + EOFLOGClassFnStopOrCond(@"EOSQLExpression"); + return [NSString stringWithFormat:@"%@(%d, %d)", extType, precision, + scale]; + } + else if ([attribute width]) + { + EOFLOGClassFnStopOrCond(@"EOSQLExpression"); + return [NSString stringWithFormat: @"%@(%d)", extType, scale]; + } + else + { + EOFLOGClassFnStopOrCond(@"EOSQLExpression"); + return [NSString stringWithFormat: @"%@", extType]; + } +} + +- (NSString *)allowsNullClauseForConstraint: (BOOL)allowsNull +{ + if (allowsNull == NO) + return @"NOT NULL"; + + return nil; +} + +- (void)addCreateClauseForAttribute: (EOAttribute *)attribute +{ + NSString *columnType; + NSString *allowsNull; + NSString *str; + + EOFLOGClassFnStartOrCond(@"EOSQLExpression"); + + columnType = [self columnTypeStringForAttribute: attribute]; + allowsNull = [self allowsNullClauseForConstraint: [attribute allowsNull]]; + + if (allowsNull) + str = [NSString stringWithFormat: @"%@ %@ %@", [attribute columnName], + columnType, allowsNull]; + else + str = [NSString stringWithFormat: @"%@ %@", [attribute columnName], + allowsNull]; + + [self appendItem:str toListString: _listString]; + + EOFLOGClassFnStopOrCond(@"EOSQLExpression"); +} + +- (void)prepareConstraintStatementForRelationship: (EORelationship *)relationship + sourceColumns: (NSArray *)sourceColumns + destinationColumns: (NSArray *)destinationColumns +{ + NSMutableString *sourceString, *destinationString; + NSEnumerator *attrEnum; + EOAttribute *attr; + NSString *name, *str; + BOOL first = YES; + + EOFLOGClassFnStartOrCond(@"EOSQLExpression"); + + name = [NSString stringWithFormat: @"%@_%@_FK", [_entity externalName], + [relationship name]]; + + sourceString = [NSMutableString stringWithCapacity: 30]; + + attrEnum = [sourceColumns objectEnumerator]; + while ((attr = [attrEnum nextObject])) + { + NSString *columnName = [attr columnName]; + + if (!columnName || ![columnName length]) + continue; + + if (first == NO) + [sourceString appendString: @", "]; + + [sourceString appendString: columnName]; + first = NO; + } + + first = YES; + destinationString = [NSMutableString stringWithCapacity: 30]; + + attrEnum = [destinationColumns objectEnumerator]; + while ((attr = [attrEnum nextObject])) + { + NSString *columnName = [attr columnName]; + + if (!columnName || ![columnName length]) + continue; + + if (first == NO) + [destinationString appendString: @", "]; + + [destinationString appendString: columnName]; + first = NO; + } + + str = [NSString stringWithFormat: @"ALTER TABLE %@ ADD CONSTRAINT %@ FOREIGN KEY (%@) REFERENCES %@ (%@)", + [_entity externalName], + name, + sourceString, + [[relationship destinationEntity] externalName], + destinationString]; + + ASSIGN(_statement, str); + + EOFLOGClassFnStopOrCond(@"EOSQLExpression"); +} + +// Assembles an adaptor specific constraint statement for relationship. + ++ (NSArray *)createDatabaseStatementsForConnectionDictionary: (NSDictionary *)connectionDictionary + administrativeConnectionDictionary: (NSDictionary *)administrativeConnectionDictionary +{ + [self subclassResponsibility: _cmd]; + return nil; +} + ++ (NSArray *)dropDatabaseStatementsForConnectionDictionary: (NSDictionary *)connectionDictionary + administrativeConnectionDictionary: (NSDictionary *)administrativeConnectionDictionary +{ + [self subclassResponsibility: _cmd]; + return nil; +} + ++ (EOSQLExpression *)selectStatementForContainerOptions +{ + [self notImplemented: _cmd]; + return nil; +} + +@end diff --git a/EOAccess/EOSQLExpressionPriv.h b/EOAccess/EOSQLExpressionPriv.h new file mode 100644 index 0000000..5035519 --- /dev/null +++ b/EOAccess/EOSQLExpressionPriv.h @@ -0,0 +1,48 @@ +/* + EOSQLExpression.h + + Copyright (C) 2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: Mars 2002 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOSQLExpressionPriv_h__ +#define __EOSQLExpressionPriv_h__ + +@class EOEntity; + + +@interface EOSQLExpression (EOSQLExpressionPrivate) + +- (EOEntity *)_rootEntityForExpression; +- (id) _aliasForRelationshipPath: (id)param0; +- (id) _flattenRelPath: (id)param0 + entity: (id)param1; +- (NSString*) _sqlStringForJoinSemantic: (EOJoinSemantic)joinSemantic + matchSemantic: (int)param1; +- (id) _aliasForRelatedAttribute: (id)param0 + relationshipPath: (id)param1; +- (id) _entityForRelationshipPath: (id)param0 + origin: (id)param1; + +@end + +#endif /* __EOSQLExpressionPriv_h__ */ diff --git a/EOAccess/EOSQLQualifier.h b/EOAccess/EOSQLQualifier.h new file mode 100644 index 0000000..5e2f5ae --- /dev/null +++ b/EOAccess/EOSQLQualifier.h @@ -0,0 +1,91 @@ +/* + EOSQLQualifier.h + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + Author: Manuel Guesdon + Date: February 2002 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOSQLQualifier_h__ +#define __EOSQLQualifier_h__ + +#import +#import + + +@class EOSQLExpression; +@class EOExpressionArray; +@class EOEntity; +@class EOModel; + +/** Protocol for all qualifiers used used to generate SQL queries **/ +@protocol EOQualifierSQLGeneration + +- (NSString *)sqlStringForSQLExpression: (EOSQLExpression *)sqlExpression; + +/** Returns an equivalent EOQualifier with object references replaced by foreign key references. **/ +- (EOQualifier *)schemaBasedQualifierWithRootEntity: (EOEntity *)entity; + +@end + + +@interface EOAndQualifier (EOQualifierSQLGeneration) +@end +@interface EOOrQualifier (EOQualifierSQLGeneration) +@end +@interface EOKeyComparisonQualifier (EOQualifierSQLGeneration) +@end +@interface EOKeyValueQualifier (EOQualifierSQLGeneration) +@end +@interface EONotQualifier (EOQualifierSQLGeneration) +@end + + +// +// Finally, declare the EOSQLQualifier class. +// +@interface EOSQLQualifier : EOQualifier +{ + EOEntity *_entity; + EOExpressionArray *_contents; + struct + { + unsigned int usesDistinct:1; + unsigned int _RESERVED:31; + } _flags; +} + ++ (EOQualifier *)qualifierWithQualifierFormat: (NSString *)format, ...; + +- (id)initWithEntity: (EOEntity *)entity + qualifierFormat: (NSString *)qualifierFormat, ...; +// This is the designated initializer for EOSQLQualifier. + +@end + +@interface NSString (NSStringSQLExpression) +- (NSString *) valueForSQLExpression: (EOSQLExpression *)sqlExpression; +@end + +#endif diff --git a/EOAccess/EOSQLQualifier.m b/EOAccess/EOSQLQualifier.m new file mode 100644 index 0000000..1ed82e6 --- /dev/null +++ b/EOAccess/EOSQLQualifier.m @@ -0,0 +1,369 @@ +/** + EOSQLQualifier.m EOSQLQualifier Class + + Copyright (C) 2002 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: February 2002 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#include +#include + +#import +#import +#import + +#import +#import +#import +#import + +#import + +#import +#import +#import + + +@implementation EOSQLQualifier + ++ (EOQualifier *)qualifierWithQualifierFormat: (NSString *)format, ... +{ + NSEmitTODO(); //TODO + [self notImplemented: _cmd]; //TODO + + return nil; +} + +- (id)initWithEntity: (EOEntity *)entity + qualifierFormat: (NSString *)qualifierFormat, ... +{ + NSEmitTODO(); //TODO + [self notImplemented: _cmd]; //TODO + + return nil; +} + +- (EOQualifier *)schemaBasedQualifierWithRootEntity:(EOEntity *)entity +{ + [self notImplemented: _cmd]; + return nil; +} + +- (NSString *)sqlStringForSQLExpression:(EOSQLExpression *)sqlExpression +{ + [self notImplemented: _cmd]; + return nil; +} + +@end + + +@implementation EOAndQualifier (EOQualifierSQLGeneration) + +- (NSString *)sqlStringForSQLExpression: (EOSQLExpression *)sqlExpression +{ + //OK? + return [sqlExpression sqlStringForConjoinedQualifiers: _qualifiers]; + +/* +//TODO finish to add sqlExpression + NSEnumerator *qualifiersEnum=nil; + EOQualifier *qualifier=nil; + NSMutableString *sqlString = nil; + + qualifiersEnum = [_qualifiers objectEnumerator]; + while ((qualifier = [qualifiersEnum nextObject])) + { + if (!sqlString) + { + sqlString = [NSMutableString stringWithString: + [()qualifier sqlStringForSQLExpression:sqlExpression]]; + } + else + { + [sqlString appendFormat:@" %@ %@", + @"AND", + [()qualifier sqlStringForSQLExpression:sqlExpression]]; + } + } + return sqlString; +*/ +} + +- (EOQualifier *)schemaBasedQualifierWithRootEntity: (EOEntity *)entity +{ + int qualifierCount = [_qualifiers count]; + + if (qualifierCount > 0) + { + NSMutableArray *qualifiers = [NSMutableArray array]; + int i; + + for (i = 0; i < qualifierCount; i++) + { + EOQualifier *qualifier = [_qualifiers objectAtIndex: i]; + EOQualifier *schemaBasedQualifierTmp = + [()qualifier + schemaBasedQualifierWithRootEntity: + entity]; + + [qualifiers addObject: schemaBasedQualifierTmp]; + } + } +//TODO +/* +call schemaBasedQualifierWithRootEntity:entity for each qualifier +if none return something different self, return self + [self notImplemented:_cmd];//TODO +*/ + return self; +} + +@end + +@implementation EOOrQualifier (EOQualifierSQLGeneration) + +- (NSString *)sqlStringForSQLExpression: (EOSQLExpression *)sqlExpression +{ + NSEnumerator *qualifiersEnum; + EOQualifier *qualifier; + NSMutableString *sqlString = nil; + + qualifiersEnum = [_qualifiers objectEnumerator]; + while ((qualifier = [qualifiersEnum nextObject])) + { + if (!sqlString) + { + sqlString = [NSMutableString stringWithString: + [()qualifier sqlStringForSQLExpression: sqlExpression]]; + } + else + { + [sqlString appendFormat: @" %@ %@", + @"OR", + [()qualifier sqlStringForSQLExpression: sqlExpression]]; + } + } + + return sqlString; +} + +- (EOQualifier *)schemaBasedQualifierWithRootEntity: (EOEntity *)entity +{ +/* +call schemaBasedQualifierWithRootEntity:entity for each qualifier +if none return something different self, return self + [self notImplemented:_cmd];//TODO +*/ + return self; +} + +@end + +@implementation EOKeyComparisonQualifier (EOQualifierSQLGeneration) + +- (NSString *)sqlStringForSQLExpression: (EOSQLExpression *)sqlExpression +{ + return [sqlExpression sqlStringForKeyComparisonQualifier: self]; +} + +- (EOQualifier *)schemaBasedQualifierWithRootEntity: (EOEntity *)entity +{ + //TODO + [self notImplemented: _cmd]; + return nil; +} + +@end + +@implementation EOKeyValueQualifier (EOQualifierSQLGeneration) + +- (NSString *)sqlStringForSQLExpression: (EOSQLExpression *)sqlExpression +{ + return [sqlExpression sqlStringForKeyValueQualifier: self]; +} + +- (EOQualifier *)schemaBasedQualifierWithRootEntity: (EOEntity *)entity +{ + EOQualifier *qualifier = nil; + NSMutableArray *qualifiers = nil; + id key; + EORelationship *relationship; + + EOFLOGObjectFnStart(); + + key = [self key]; + EOFLOGObjectLevelArgs(@"EOQualifier", @"key=%@", key); + + relationship = [entity relationshipForPath: key]; + EOFLOGObjectLevelArgs(@"EOQualifier", @"relationship=%@", relationship); + + if (relationship) + { + EORelationship *destinationRelationship; + NSDictionary *keyValues = nil; + id value = nil; + EOEditingContext* editingContext = nil; + EOObjectStore *rootObjectStore = nil; + NSMutableArray *destinationAttributeNames = [NSMutableArray array]; + NSArray *joins; + int i, count; + SEL sel = NULL; + + if ([relationship isFlattened]) + destinationRelationship = [relationship lastRelationship]; + else + destinationRelationship = relationship; + + joins = [destinationRelationship joins]; + count = [joins count]; + + for (i = 0; i < count; i++) + { + EOJoin *join = [joins objectAtIndex: i]; + EOAttribute *destinationAttribute = [join destinationAttribute]; + NSString *destinationAttributeName = [destinationAttribute name]; + + [destinationAttributeNames addObject: destinationAttributeName]; + } + + value = [self value]; + EOFLOGObjectLevelArgs(@"EOQualifier", @"value=%@", value); + + editingContext = [value editingContext]; + rootObjectStore = [editingContext rootObjectStore]; + + EOFLOGObjectLevelArgs(@"EOQualifier", @"rootObjectStore=%@", + rootObjectStore); + EOFLOGObjectLevelArgs(@"EOQualifier", @"destinationAttributeNames=%@", + destinationAttributeNames); + + keyValues = [(EOObjectStoreCoordinator*)rootObjectStore + valuesForKeys: + destinationAttributeNames + object: value]; + EOFLOGObjectLevelArgs(@"EOQualifier", @"keyValues=%@", keyValues); + + sel = [self selector]; + /* +when flattened: ??? + entity relationshipForPath:key + and get joins on it ? + */ + + for (i = 0; i < count; i++) + { + EOQualifier *tmpQualifier = nil; + NSString *attributeName = nil; + NSString *destinationAttributeName; + EOJoin *join = [joins objectAtIndex: i]; + + EOFLOGObjectLevelArgs(@"EOQualifier",@"join=%@",join); + + destinationAttributeName = [destinationAttributeNames + objectAtIndex: i]; + + if (destinationRelationship != relationship) + { + // flattened: take destattr + attributeName = [NSString stringWithFormat: @"%@.%@", + key, destinationAttributeName]; + //==> rel.attr + } + else + { + EOAttribute *sourceAttribute = [join sourceAttribute]; + + attributeName = [sourceAttribute name]; + } + + tmpQualifier = [EOKeyValueQualifier + qualifierWithKey: attributeName + operatorSelector: sel + value: [keyValues objectForKey: + destinationAttributeName]]; + + if (qualifier)//Already a qualifier + { + //Create an array of qualifiers + qualifiers = [NSMutableArray arrayWithObjects: qualifier, + tmpQualifier, nil]; + qualifier = nil; + } + else if (qualifiers) //Already qualifiers + //Add this one + [qualifiers addObject: tmpQualifier]; + else + //No previous qualifier + qualifier = tmpQualifier; + } + + if (qualifiers) + { + //TODOVERIFY + qualifier = [EOAndQualifier qualifierWithQualifierArray: qualifiers]; + } + } + else + qualifier = self; + + EOFLOGObjectFnStop(); + + return qualifier; +} + +@end + +@implementation EONotQualifier (EOQualifierSQLGeneration) + +- (NSString *)sqlStringForSQLExpression: (EOSQLExpression *)sqlExpression +{ + return [sqlExpression sqlStringForNegatedQualifier: self]; +} + +- (EOQualifier *)schemaBasedQualifierWithRootEntity: (EOEntity *)entity +{ + //TODO + [self notImplemented: _cmd]; + return nil; +} + +@end + + +@implementation NSString (NSStringSQLExpression) + +- (NSString *) valueForSQLExpression: (EOSQLExpression *)sqlExpression +{ + return self; +} + +@end diff --git a/EOAccess/EOStoredProcedure.h b/EOAccess/EOStoredProcedure.h new file mode 100644 index 0000000..355e00f --- /dev/null +++ b/EOAccess/EOStoredProcedure.h @@ -0,0 +1,79 @@ +/* + EOStoredProcedure.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOStoredProcedure_h__ +#define __EOStoredProcedure_h__ + +#import +#import +#import + +@class EOModel; +@class EOAttribute; +@class GCArray; + + +@interface EOStoredProcedure : GCObject +{ + NSString *_name; + NSString *_externalName; + NSDictionary *_userInfo; + NSDictionary *_internalInfo; + + /* Garbage collectable objects */ + EOModel *_model; + GCArray *_arguments; +} + ++ (EOStoredProcedure *)storedProcedureWithPropertyList: (NSDictionary *)propertyList + owner: (id)owner; + +- (EOStoredProcedure *)initWithName:(NSString *)name; + +- (NSString *)name; + +- (NSString *)externalName; + +- (EOModel *)model; + +- (NSArray *)arguments; + +- (NSDictionary *)userInfo; + +- (void)setName:(NSString *)name; +- (void)setExternalName:(NSString *)name; +- (void)setArguments:(NSArray *)arguments; +- (void)setUserInfo:(NSDictionary *)dictionary; + +@end + +@interface EOStoredProcedure(EOModelBeautifier) + +- (void)beautifyName; + +@end + +#endif diff --git a/EOAccess/EOStoredProcedure.m b/EOAccess/EOStoredProcedure.m new file mode 100644 index 0000000..a450b53 --- /dev/null +++ b/EOAccess/EOStoredProcedure.m @@ -0,0 +1,226 @@ +/** + EOStoredProcedure.m EOStoredProcedure Class + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import + +#import +#import +#import + +#import + + +@implementation EOStoredProcedure + +- (EOStoredProcedure *)initWithName:(NSString *)name +{ + self = [super init]; + + [self setName:name]; + _userInfo = [NSDictionary new]; + _internalInfo = [NSDictionary new]; + + return self; +} + +- (void)gcDecrementRefCountOfContainedObjects +{ + EOFLOGObjectFnStart(); + + NSDebugMLLog(@"gsdb", @"model gcDecrementRefCount"); + + [(id)_model gcDecrementRefCount]; + [(id)_arguments gcDecrementRefCount]; + + EOFLOGObjectFnStop(); +} + +- (BOOL)gcIncrementRefCountOfContainedObjects +{ + if (![super gcIncrementRefCountOfContainedObjects]) + return NO; + + [(id)_model gcIncrementRefCount]; + [(id)_arguments gcIncrementRefCount]; + + [(id)_model gcIncrementRefCountOfContainedObjects]; + [(id)_arguments gcIncrementRefCountOfContainedObjects]; + + return YES; +} + ++ (EOStoredProcedure *)storedProcedureWithPropertyList: (NSDictionary *)propertyList + owner: (id)owner +{ + return [[[self alloc] initWithPropertyList: propertyList + owner: owner] autorelease]; +} + +- initWithPropertyList: (NSDictionary *)propertyList owner: (id)owner +{ + NSArray *array; + NSEnumerator *enumerator; + id attributePList; + + _model = [owner retain]; + + [self setName: [propertyList objectForKey: @"name"]]; + [self setExternalName: [propertyList objectForKey: @"externalName"]]; + [self setUserInfo: [propertyList objectForKey: @"userInfo"]]; + + if (!_userInfo) + [self setUserInfo:[propertyList objectForKey:@"userInfo"]]; + + array = [propertyList objectForKey:@"attributes"]; + if ([array count]) + { + _arguments = [[GCMutableArray alloc] initWithCapacity: [array count]]; + + enumerator = [array objectEnumerator]; + while ((attributePList = [enumerator nextObject])) + { + EOAttribute *attribute = [EOAttribute + attributeWithPropertyList: attributePList + owner: self]; + + [(GCMutableArray *)_arguments addObject: attribute]; + } + } + + return self; +} + +- (void)awakeWithPropertyList: (NSDictionary *)propertyList +{ + NSEnumerator *argsEnum; + EOAttribute *attribute; + + argsEnum = [_arguments objectEnumerator]; + while ((attribute = [argsEnum nextObject])) + [attribute awakeWithPropertyList: propertyList]; +} + +- (void)encodeIntoPropertyList: (NSMutableDictionary *)propertyList +{ + return; +} + +- (NSString *)name +{ + return _name; +} + +- (NSString *)externalName +{ + return _externalName; +} + +- (EOModel *)model +{ + return _model; +} + +- (NSArray *)arguments +{ + return _arguments; +} + +- (NSDictionary *)userInfo +{ + return _userInfo; +} + +- (void)setName: (NSString *)name +{ + ASSIGN(_name, name); +} + +- (void)setExternalName: (NSString *)name +{ + ASSIGN(_externalName, name); +} + +- (void)setArguments: (NSArray *)arguments +{ + if ([arguments isKindOfClass: [GCArray class]] + || [arguments isKindOfClass: [GCMutableArray class]]) + ASSIGN(_arguments, arguments); + else + _arguments = [[GCArray alloc] initWithArray: arguments]; +} + +- (void)setUserInfo: (NSDictionary *)dictionary +{ + ASSIGN(_userInfo, dictionary); +} + +@end + + +@implementation EOStoredProcedure (EOModelBeautifier) + +- (void)beautifyName +{ + NSArray *listItems; + NSString *newString = [NSMutableString string]; + int anz, i; + + EOFLOGObjectFnStartOrCond2(@"ModelingClasses", @"EOStoredProcedure"); + + if ((_name) && ([_name length] > 0)) + { + listItems = [_name componentsSeparatedByString: @"_"]; + newString = [newString stringByAppendingString: [[listItems objectAtIndex: 0] + lowercaseString]]; + anz = [listItems count]; + + for (i = 1; i < anz; i++) + { + newString = [newString stringByAppendingString: + [[listItems objectAtIndex: i] capitalizedString]]; + } + + NS_DURING + [self setName: newString]; + NS_HANDLER + NSLog(@"%@ in Class: EOStoredProcedure , Method: beautifyName >> error : %@", + [localException name], [localException reason]); + NS_ENDHANDLER; + } + + EOFLOGObjectFnStopOrCond2(@"ModelingClasses", @"EOStoredProcedure"); +} + +@end diff --git a/EOAccess/EOUtilities.h b/EOAccess/EOUtilities.h new file mode 100644 index 0000000..d53324f --- /dev/null +++ b/EOAccess/EOUtilities.h @@ -0,0 +1,105 @@ +/* + EOUtilities.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: Sep 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOUtilities_h__ +#define __EOUtilities_h__ + +#import + +@class EODatabaseContext; +@class EOModelGroup; +@class EOEntity; + +extern NSString *EOMoreThanOneException; + + +@interface EOEditingContext(EOUtilities) + +- (NSArray*)objectsForEntityNamed: (NSString*)name; +- (NSArray*)objectsOfClass: (Class)classObject; +- (NSArray*)objectsWithFetchSpecificationNamed: (NSString*)fetchSpecName + entityNamed: (NSString*)entityName + bindings: (NSDictionary*)bindings; +- (NSArray*)objectsForEntityNamed: (NSString*)name + qualifierFormat: (NSString*)format, ...; +- (NSArray*)objectsMatchingValue: (id)value + forKey: (NSString*)key + entityNamed: (NSString*)name; +- (NSArray*)objectsMatchingValues: (NSDictionary*)values + entityNamed: (NSString*)name; + +- (id)objectWithFetchSpecificationNamed: (NSString*)fetchSpecName + entityNamed: (NSString*)entityName + bindings: (NSDictionary*)bindings; +- (id)objectForEntityNamed: (NSString*)name + qualifierFormat: (NSString*)format, ...; +- (id)objectMatchingValue: (id)value + forKey: (NSString*)key + entityNamed: (NSString*)name; +- (id)objectMatchingValues: (NSDictionary*)values + entityNamed: (NSString*)name; +- (id)objectWithPrimaryKeyValue: (id)value + entityNamed: (NSString*)name; +- (id)objectWithPrimaryKey: (NSDictionary*)pkDict + entityNamed: (NSString*)name; + +- (NSArray *)objectsOfClass: (Class)class; + +- (NSArray*)rawRowsForEntityNamed: (NSString*)name + qualifierFormat: (NSString*)format, ...; +- (NSArray*)rawRowsMatchingValue: (id)value + forKey: (NSString*)key + entityNamed: (NSString*)name; +- (NSArray*)rawRowsMatchingValues: (NSDictionary*)values + entityNamed: (NSString*)name; +- (NSArray*)rawRowsWithSQL: (NSString*)sqlString + modelNamed: (NSString*)name; +- (NSArray*)rawRowsWithStoredProcedureNamed: (NSString*)name + arguments: (NSDictionary*)args; +- (NSDictionary*)executeStoredProcedureNamed: (NSString*)name + arguments: (NSDictionary*)args; +- (id)objectFromRawRow: (NSDictionary*)row + entityNamed: (NSString*)name; + +- (EODatabaseContext*)databaseContextForModelNamed: (NSString*)name; +- (void)connectWithModelNamed: (NSString*)name +connectionDictionaryOverrides: (NSDictionary*)overrides; + +- (NSDictionary*)primaryKeyForObject: (id)object; +- (NSDictionary*)destinationKeyForSourceObject: (id)object + relationshipNamed: (NSString*)name; + +- (id)localInstanceOfObject: (id)object; +- (NSArray*)localInstancesOfObjects: (NSArray*)objects; + +- (EOModelGroup*)modelGroup; +- (EOEntity*)entityNamed: (NSString*)name; +- (EOEntity*)entityForClass: (Class)classObject; +- (EOEntity*)entityForObject: (id)obj; + +@end + +#endif diff --git a/EOAccess/EOUtilities.m b/EOAccess/EOUtilities.m new file mode 100644 index 0000000..529b585 --- /dev/null +++ b/EOAccess/EOUtilities.m @@ -0,0 +1,1039 @@ +/** + EOUtilities.m + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: Sep 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import + +#import +#import +#import + +#import +#import + + +static NSString *EOMoreThanOneException = @"EOMoreThanOneException"; +//static NSString *NSObjectNotAvailableException = @"NSObjectNotAvailableException"; + + +@implementation EOEditingContext (EOUtilities) + +- (NSArray*)objectsForEntityNamed: (NSString*)entityName +{ + NSArray *objects; + EOFetchSpecification *fetchSpecif; + + NSAssert([entityName length] > 0, @"No entity name"); + + fetchSpecif = [EOFetchSpecification + fetchSpecificationWithEntityName: entityName + qualifier: nil + sortOrderings: nil]; + objects = [self objectsWithFetchSpecification: fetchSpecif]; + + return objects; +} + +- (NSArray*)objectsOfClass: (Class)classObject +{ + EOEntity *entity; + NSArray *objects; + + EOFLOGObjectFnStartOrCond(@"EOEditingContext"); + + entity = [self entityForClass: classObject]; + objects = [self objectsForEntityNamed: [entity name]]; + + EOFLOGObjectFnStopOrCond(@"EOEditingContext"); + + return objects; +} + +- (NSArray*)objectsWithFetchSpecificationNamed: (NSString*)fetchSpecName + entityNamed: (NSString*)entityName + bindings: (NSDictionary*)bindings +{ + EOModelGroup *modelGroup; + EOFetchSpecification *unboundFetchSpec; + EOFetchSpecification *boundFetchSpec; + NSArray *results; + + modelGroup = [self modelGroup]; + unboundFetchSpec = [modelGroup fetchSpecificationNamed: fetchSpecName + entityNamed: entityName]; + + if ( !unboundFetchSpec ) + { + [NSException raise: /*NSObjectNotAvailableException*/NSInvalidArgumentException + format: @"%@: Fetch specification '%@' not found in entity named '%@'", + NSStringFromSelector(_cmd), fetchSpecName, entityName]; + } + + boundFetchSpec = [unboundFetchSpec fetchSpecificationWithQualifierBindings: + bindings]; + results = [self objectsWithFetchSpecification: boundFetchSpec]; + + return results; +} + +- (NSArray*)objectsForEntityNamed: (NSString*)entityName + qualifierFormat: (NSString*)format,... +{ + EOQualifier *qualifier; + EOFetchSpecification *fetchSpec; + NSArray *results; + va_list args; + + va_start(args, format); + qualifier = [EOQualifier qualifierWithQualifierFormat: format + varargList: args]; + va_end(args); + + fetchSpec = [EOFetchSpecification fetchSpecificationWithEntityName: + entityName + qualifier: qualifier + sortOrderings: nil]; + results = [self objectsWithFetchSpecification: fetchSpec]; + + return results; +} + +- (NSArray*)objectsMatchingValue: (id)value + forKey: (NSString*)key + entityNamed: (NSString*)entityName +{ + //OK + NSArray *objects; + + EOFLOGObjectFnStart(); + NSDebugMLLog(@"gsdb", @"START value=%@ key=%@ entityName=%@", + value, key, entityName); + + if (!value) + value=[EONull null]; + + NSAssert(value, @"No Value"); //Transform it to EONull ? + NSAssert(key, @"No Key"); + NSAssert([entityName length] > 0, @"No entity name"); + + objects = [self objectsMatchingValues: + [NSDictionary dictionaryWithObject: value + forKey: key] + entityNamed: entityName]; + + EOFLOGObjectFnStop(); + + return objects; +//TC: +/* + EOKeyValueQualifier *qualifier; + EOFetchSpecification *fetch; + NSArray *newArray; + + EOFLOGObjectFnStartOrCond(@"EOEditingContext"); + + qualifier = [[EOKeyValueQualifier alloc] + initWithKey:key + operatorSelector:EOQualifierOperatorEqual + value:value]; + + fetch = [EOFetchSpecification fetchSpecificationWithEntityName:name + qualifier:[qualifier autorelease] + sortOrderings:nil]; + + newArray = [self objectsWithFetchSpecification:fetch]; + + EOFLOGObjectFnStopOrCond(@"EOEditingContext"); + + return newArray; +*/ +} + +- (NSArray*)objectsMatchingValues: (NSDictionary*)values + entityNamed: (NSString*)entityName +{ + //OK + NSArray *objects = nil; + EOFetchSpecification *fetchSpec; + EOQualifier *qualifier; + NSEnumerator *valuesEnum; + id key=nil; + NSMutableArray* kvQualifiers=nil; + + EOFLOGObjectFnStart(); + + NSDebugMLLog(@"gsdb", @"START values=%@ entityName=%@", values, entityName); + + NS_DURING + { + NSAssert([entityName length] > 0, @"No entity name"); + + valuesEnum = [values keyEnumerator]; + kvQualifiers = [NSMutableArray array]; + + while ((key = [valuesEnum nextObject])) + { + id value = [values objectForKey: key]; + EOKeyValueQualifier *tmpQualifier = [EOKeyValueQualifier + qualifierWithKey: key + operatorSelector: + @selector(isEqualTo:) + value: value]; + + [kvQualifiers addObject: tmpQualifier]; + } + + qualifier = [EOAndQualifier qualifierWithQualifierArray: kvQualifiers]; + fetchSpec = [EOFetchSpecification fetchSpecificationWithEntityName: + entityName + qualifier: qualifier + sortOrderings: nil]; + + NSDebugMLLog(@"gsdb", @"fetchSpec=%@", fetchSpec); + objects = [self objectsWithFetchSpecification: fetchSpec]; + } + NS_HANDLER + { + NSDebugMLog(@"exception in EOEditingContext (EOUtilities) objectsMatchingValues:entityNamed:"); + NSLog(@"exception in EOEditingContext (EOUtilities) objectsMatchingValues:entityNamed:"); + NSDebugMLog(@"exception=%@",localException); + NSLog(@"exception=%@", localException); +/* localException=ExceptionByAddingUserInfoObjectFrameInfo(localException, + @"In EOEditingContext (EOUtilities) objectsMatchingValues:entityNamed:"); +*/ + NSLog(@"exception=%@", localException); + [localException raise]; + } + NS_ENDHANDLER; + + EOFLOGObjectFnStop(); + + return objects; +//TC: +/* + EOQualifier *qualifier; + EOFetchSpecification *fetchSpec; + NSArray *results; + + qualifier = [EOQualifier qualifierToMatchAllValues:values]; + fetchSpec = [EOFetchSpecification fetchSpecificationWithEntityName:name qualifier:qualifier sortOrderings:nil]; + results = [self objectsWithFetchSpecification:fetchSpec]; + return results; + +*/ +} + +- (id)objectWithFetchSpecificationNamed: (NSString*)fetchSpecName + entityNamed: (NSString*)entityName + bindings: (NSDictionary*)bindings +{ + id object = nil; + int count; + NSArray *objects; + + NSAssert([entityName length] > 0, @"No entity name"); + + objects = [self objectsWithFetchSpecificationNamed:fetchSpecName + entityNamed:entityName + bindings:bindings]; + count = [objects count]; + + switch (count) + { + case 0: + [NSException raise: NSInvalidArgumentException + format: @"%@: No item selected for fetch specification %@ in entity %@ with bindings %@", + NSStringFromSelector(_cmd), + fetchSpecName, + entityName, + bindings]; + break; + case 1: + object = [objects objectAtIndex: 0]; + break; + default: + [NSException raise: EOMoreThanOneException + format: @"%@: Selected more than one item for fetch specification %@ in entity %@ with bindings %@", + NSStringFromSelector(_cmd), + fetchSpecName, + entityName, + bindings]; + break; + } + + return object; +} + +- (id)objectForEntityNamed: (NSString*)entityName + qualifierFormat: (NSString*)format,... +{ + id object = nil; + int count; + EOQualifier *qualifier; + EOFetchSpecification *fetchSpec; + NSArray *objects; + va_list args; + + va_start(args, format); + qualifier = [EOQualifier qualifierWithQualifierFormat: format + varargList: args]; + va_end(args); + + fetchSpec = [EOFetchSpecification fetchSpecificationWithEntityName: + entityName + qualifier: qualifier + sortOrderings: nil]; + objects = [self objectsWithFetchSpecification: fetchSpec]; + + count = [objects count]; + + switch (count) + { + case 0: + [NSException raise: NSInvalidArgumentException + format: @"%@: No item selected for entity %@ qualified by %@", + NSStringFromSelector(_cmd), + entityName, + format]; + break; + case 1: + object = [objects objectAtIndex: 0]; + break; + default: + [NSException raise: EOMoreThanOneException + format: @"%@: Selected more than one item for entity %@ qualified by %@", + NSStringFromSelector(_cmd), + entityName, + format]; + } + + return object; +} + +- (id)objectMatchingValue: (id)value + forKey: (NSString*)key + entityNamed: (NSString*)entityName +{ + //OK + id object = nil; + int count; + NSArray *objects; + + EOFLOGObjectFnStart(); + + NSDebugMLLog(@"gsdb", @"START value=%@ key=%@ entityName=%@", + value, key, entityName); + + NS_DURING //Debugging Purpose + { + NSAssert([entityName length] > 0, @"No entity name"); + + objects = [self objectsMatchingValue: value + forKey: key + entityNamed: entityName]; + + NSDebugMLLog(@"gsdb", @"objects count=%d", [objects count]); + NSDebugMLLog(@"gsdb", @"objects=%@", objects); + + count = [objects count]; + + switch (count) + { + case 0: + [NSException raise: NSInvalidArgumentException + format: @"%@: No %@ found with key %@ matching %@", + NSStringFromSelector(_cmd), + entityName, + key, + value]; + break; + case 1: + object = [objects objectAtIndex: 0]; + break; + default: + [NSException raise: EOMoreThanOneException + format: @"%@: Selected more than one %@ with key %@ matching %@", + NSStringFromSelector(_cmd), + entityName, + key, + value]; + break; + } + } + NS_HANDLER + { + NSLog(@"exception in EOEditingContext (EOUtilities) objectMatchingValue:forKey:entityNamed:"); + NSLog(@"exception=%@", localException); +/* localException=ExceptionByAddingUserInfoObjectFrameInfo(localException, + @"In EOEditingContext (EOUtilities) objectMatchingValue:forKey:entityNamed:"); +*/ + NSLog(@"exception=%@", localException); + [localException raise]; + } + NS_ENDHANDLER; + + NSDebugMLLog(@"gsdb", @"object=%@", object); + + EOFLOGObjectFnStop(); + + return object; +} + +- (id)objectMatchingValues: (NSDictionary*)values + entityNamed: (NSString*)entityName +{ + id object = nil; + int count; + NSArray *objects; + + EOFLOGObjectFnStart(); + + NSAssert([entityName length] > 0, @"No entity name"); + + objects = [self objectsMatchingValues: values + entityNamed: entityName]; + count = [objects count]; + + switch(count) + { + case 0: + [NSException raise: NSInvalidArgumentException + format: @"%@: No %@ found matching %@", + NSStringFromSelector(_cmd), + entityName, + values]; + break; + case 1: + object = [objects objectAtIndex: 0]; + break; + default: + [NSException raise: EOMoreThanOneException + format: @"%@: Selected more than one %@ matching %@", + NSStringFromSelector(_cmd), + entityName, + values]; + break; + } + + EOFLOGObjectFnStop(); + + return object; +} + +- (id)objectWithPrimaryKeyValue: (id)value + entityNamed: (NSString*)entityName +{ + //OK + id object = nil; + EOEntity *entity; + + NSAssert([entityName length] > 0, @"No entity name"); + + entity = [self entityNamed: entityName]; + + if (!entity) + [NSException raise: NSInvalidArgumentException + format: @"objectWithPrimaryKeyValue:%@ entityNamed:%@; no entity", + value, + entityName]; + else + { + NSArray *primaryKeyAttributes = [entity primaryKeyAttributes]; + + if ([primaryKeyAttributes count] != 1) + { + [NSException raise: NSInvalidArgumentException + format: @"objectWithPrimaryKeyValue:%@ entityNamed:%@ may only be called for entities with one primary key attribute. For entities with compound primary keys, use objectWithPrimaryKey:entityNamed and provide a dictionary for the primary key.", + value, + entityName]; + } + else + { + NSDictionary* pk; + if (!value) + value=[EONull null]; + + pk = [NSDictionary dictionaryWithObject: value + forKey: [(EOAttribute*)[primaryKeyAttributes + objectAtIndex: 0] + name]]; + + object = [self objectWithPrimaryKey: pk + entityNamed: entityName]; + } + } + + return object; +} + +- (id)objectWithPrimaryKey: (NSDictionary*)pkDict + entityNamed: (NSString*)entityName +{ + //OK + id object = nil; + EOEntity *entity; + + NSAssert([pkDict count] > 0, @"Empty primary key."); + NSAssert([entityName length] > 0, @"No entity name"); + + entity = [self entityNamed: entityName]; + + if (!entity) + [NSException raise: NSInvalidArgumentException + format: @"objectWithPrimaryKeyValue:%@ entityNamed:%@; no entity", + pkDict, + entityName]; + else + { + EOGlobalID *gid = [entity globalIDForRow: pkDict]; + + object = [self faultForGlobalID: gid + editingContext: self]; + } + + return object; +} + +- (id)rawRowsForEntityNamed: (NSString*)entityName + qualifierFormat: (NSString*)format,... +{ + EOQualifier *qualifier; + EOFetchSpecification *fetchSpec; + NSArray *results; + va_list args; + + va_start(args, format); + qualifier = [EOQualifier qualifierWithQualifierFormat: format + varargList: args]; + va_end(args); + + NSAssert([entityName length] > 0, @"No entity name"); + + fetchSpec = [EOFetchSpecification fetchSpecificationWithEntityName: + entityName + qualifier: qualifier + sortOrderings: nil]; + [fetchSpec setFetchesRawRows: YES]; + + results = [self objectsWithFetchSpecification: fetchSpec]; + + return results; +} + +- (id)rawRowsMatchingValue: (id)value + forKey: (NSString*)key + entityNamed: (NSString*)entityName +{ + NSDictionary *valueDict; + NSArray *results; + + NSAssert([entityName length]>0,@"No entity name"); + + if (!value) + value=[EONull null]; + + valueDict = [NSDictionary dictionaryWithObject: value + forKey: key]; + results = [self rawRowsMatchingValues: valueDict + entityNamed: entityName]; + + return results; +} + +- (id)rawRowsMatchingValues: (NSDictionary*)values + entityNamed: (NSString*)entityName +{ + EOQualifier *qualifier; + EOFetchSpecification *fetchSpec; + NSArray *results; + + NSAssert([entityName length] > 0, @"No entity name"); + + qualifier = [EOQualifier qualifierToMatchAllValues: values]; + fetchSpec = [EOFetchSpecification fetchSpecificationWithEntityName: + entityName + qualifier: qualifier + sortOrderings: nil]; + [fetchSpec setFetchesRawRows: YES]; + + results = [self objectsWithFetchSpecification: fetchSpec]; + + return results; +} + +- (id)rawRowsWithSQL: (NSString*)sqlString + modelNamed: (NSString*)name +{ + EODatabaseContext *databaseContext; + EODatabaseChannel *databaseChannel; + EOAdaptorChannel *adaptorChannel; + NSMutableArray *results = nil; + NSDictionary *row; + + databaseContext = [self databaseContextForModelNamed: name]; + + [databaseContext lock]; + + NS_DURING + { + databaseChannel = [databaseContext availableChannel]; + adaptorChannel = [databaseChannel adaptorChannel]; + + if (![adaptorChannel isOpen]) + [adaptorChannel openChannel]; + + [adaptorChannel evaluateExpression: + [EOSQLExpression expressionForString: sqlString]]; + [adaptorChannel setAttributesToFetch:[adaptorChannel describeResults]]; + + results = [NSMutableArray array]; + + while ((row = [adaptorChannel fetchRowWithZone: [self zone]])) + [results addObject: row]; + + [databaseContext unlock]; + } + NS_HANDLER + { + [databaseContext unlock]; + [localException raise]; + } + NS_ENDHANDLER; + + return results; +} + +- (id)rawRowsWithStoredProcedureNamed: (NSString*)name + arguments: (NSDictionary*)args +{ + EODatabaseContext *databaseContext; + EODatabaseChannel *databaseChannel; + EOAdaptorChannel *adaptorChannel; + EOStoredProcedure *storedProcedure; + NSMutableArray *results; + NSDictionary *row; + + storedProcedure = [[self modelGroup] storedProcedureNamed: name]; + databaseContext = [self databaseContextForModelNamed: + [[storedProcedure model] name]]; + [databaseContext lock]; + + NS_DURING + { + databaseChannel = [databaseContext availableChannel]; + adaptorChannel = [databaseChannel adaptorChannel]; + + if (![adaptorChannel isOpen]) + [adaptorChannel openChannel]; + + [adaptorChannel executeStoredProcedure: storedProcedure + withValues: args]; + [adaptorChannel setAttributesToFetch: [adaptorChannel describeResults]]; + + results = [NSMutableArray array]; + + while ((row = [adaptorChannel fetchRowWithZone: [self zone]])) + [results addObject: row]; + + [databaseContext unlock]; + } + NS_HANDLER + { + [databaseContext unlock]; + [localException raise]; + } + NS_ENDHANDLER; + + return results; +} + +- (id)executeStoredProcedureNamed: (NSString*)name + arguments: (NSDictionary*)args +{ + EODatabaseContext *databaseContext; + EODatabaseChannel *databaseChannel; + EOAdaptorChannel *adaptorChannel; + EOStoredProcedure *storedProcedure; + NSDictionary *returnValues = nil; + + storedProcedure = [[self modelGroup] storedProcedureNamed: name]; + databaseContext = [self databaseContextForModelNamed: + [[storedProcedure model] name]]; + [databaseContext lock]; + + NS_DURING + { + databaseChannel = [databaseContext availableChannel]; + adaptorChannel = [databaseChannel adaptorChannel]; + + if (![adaptorChannel isOpen]) + [adaptorChannel openChannel]; + + [adaptorChannel executeStoredProcedure: storedProcedure + withValues: args]; + returnValues = [adaptorChannel + returnValuesForLastStoredProcedureInvocation]; + + [databaseContext unlock]; + } + NS_HANDLER + { + [databaseContext unlock]; + [localException raise]; + } + NS_ENDHANDLER; + + return returnValues; +} + +- (id)objectFromRawRow: (NSDictionary*)row + entityNamed: (NSString*)entityName +{ + NSAssert([entityName length] > 0, @"No entity name"); + + return [self faultForRawRow: row + entityNamed: entityName]; +} + +- (id)databaseContextForModelNamed: (NSString*)name +{ + EOModelGroup *modelGroup; + EOModel *model; + EODatabaseContext *databaseContext; + + modelGroup = [self modelGroup]; + model = [modelGroup modelNamed: name]; + + if ( !model ) + [NSException raise: NSInvalidArgumentException + format: @"%@: cannot find model named %@ associated with this EOEditingContext", + NSStringFromSelector(_cmd), + name]; + + databaseContext = [EODatabaseContext registeredDatabaseContextForModel: model + editingContext: self]; + + return databaseContext; +} + +- (void)connectWithModelNamed: (NSString *)name +connectionDictionaryOverrides: (NSDictionary *)overrides +{ + EOModel *model; + + model = [[self modelGroup] modelNamed: name]; + + [self notImplemented: _cmd]; +} + + +- (id)createAndInsertInstanceOfEntityNamed: (NSString *)entityName +{ + id object; + EOClassDescription *classDescription; + + EOFLOGObjectFnStartOrCond(@"EOEditingContext"); + + classDescription = [EOClassDescription classDescriptionForEntityName: + entityName]; + + if (!classDescription) + [NSException raise: NSInvalidArgumentException + format: @"%@ could not find class description for entity named %@", + NSStringFromSelector(_cmd), + entityName]; + + object = [classDescription createInstanceWithEditingContext: self + globalID: nil + zone: [self zone]]; + [self insertObject: object]; + + EOFLOGObjectFnStopOrCond(@"EOEditingContext"); + + return object; +} + +- (id)primaryKeyForObject: (id)object +{ + EOKeyGlobalID *gid; + EOEntity *entity; + NSDictionary *newDict; + + EOFLOGObjectFnStartOrCond(@"EOEditingContext"); + + gid = (EOKeyGlobalID *)[self globalIDForObject: object]; + entity = [self entityForObject: object]; + + newDict = [entity primaryKeyForGlobalID: gid]; + + EOFLOGObjectFnStopOrCond(@"EOEditingContext"); + + return newDict; +} + +- (id)destinationKeyForSourceObject: (id)object + relationshipNamed: (NSString*)name +{ + EODatabaseContext *databaseContext; + EODatabase *database; + EOEntity *sourceEntity; + EORelationship *relationship; + NSArray *joins; + EOJoin *join; + NSString *sourceAttributeName; + NSString *destinationAttributeName; + NSDictionary *snapshot; + NSMutableDictionary *result = nil; + int i, count; + + sourceEntity = [self entityForObject: object]; + relationship = [sourceEntity relationshipNamed: name]; + + if (!relationship) + [NSException raise: NSInvalidArgumentException + format: @"%@: entity %@ does not have relationship named %@", + NSStringFromSelector(_cmd), + [sourceEntity name], + name]; + + databaseContext = [self databaseContextForModelNamed: + [[sourceEntity model] name]]; + [databaseContext lock]; + + NS_DURING + { + database = [databaseContext database]; + snapshot = [database snapshotForGlobalID:[self globalIDForObject: + object]]; + joins = [relationship joins]; + count = [joins count]; + result = (NSMutableDictionary *)[NSMutableDictionary dictionary]; + + for (i = 0 ; i < count ; i++) + { + join = [joins objectAtIndex: i]; + sourceAttributeName = [[join sourceAttribute] name]; + destinationAttributeName = [[join destinationAttribute] name]; + + [result setObject: [snapshot objectForKey: sourceAttributeName] + forKey: destinationAttributeName]; + } + + [databaseContext unlock]; + } + NS_HANDLER + { + [databaseContext unlock]; + [localException raise]; + } + NS_ENDHANDLER; + + return result; +} + +- (id)localInstanceOfObject: (id)object +{ + EOGlobalID *gid; + id newInstance; + + EOFLOGObjectFnStartOrCond(@"EOEditingContext"); + + gid = [[object editingContext] globalIDForObject:object]; + + newInstance = [self faultForGlobalID: gid + editingContext: self]; + + EOFLOGObjectFnStopOrCond(@"EOEditingContext"); + + return newInstance; +} + +- (NSArray*)localInstancesOfObjects: (NSArray*)objects +{ + NSMutableArray *array; + int i, count = [objects count]; + id obj; + + EOFLOGObjectFnStartOrCond(@"EOEditingContext"); + + array = [NSMutableArray arrayWithCapacity: count]; + + for (i = 0; i < count; i++) + { + obj = [self localInstanceOfObject: [objects objectAtIndex: i]]; + [array addObject: obj]; + } + + EOFLOGObjectFnStopOrCond(@"EOEditingContext"); + + return array; +} + +- (EOModelGroup*)modelGroup +{ + EOObjectStore *rootObjectStore; + EOObjectStoreCoordinator *objectStoreCoordinator; + EOModelGroup *modelGroup; + + EOFLOGObjectFnStartOrCond(@"EOEditingContext"); + + rootObjectStore = [self rootObjectStore]; + + if (![rootObjectStore isKindOfClass: [EOObjectStoreCoordinator class]]) + [NSException raise: NSInvalidArgumentException + format: @"%@: an EOEditingContext's root object store must be an EOObjectStoreCoordinator for this method to function.", + NSStringFromSelector(_cmd)]; + + objectStoreCoordinator = (EOObjectStoreCoordinator *)rootObjectStore; + modelGroup = [objectStoreCoordinator modelGroup]; + + EOFLOGObjectFnStopOrCond(@"EOEditingContext"); + + return modelGroup; +} + +- (EOEntity*)entityNamed: (NSString*)entityName +{ + EOEntity *entity; + EOModelGroup *modelGroup; + + EOFLOGObjectFnStart(); + + NSAssert([entityName length] > 0, @"No entity name"); + + modelGroup = [self modelGroup]; + NSAssert(modelGroup, @"No model group"); + + entity = [modelGroup entityNamed: entityName]; + + if (!entity) + [NSException raise: NSInvalidArgumentException + format: @"%@: could not find entity named:%@", + NSStringFromSelector(_cmd), + entityName]; + + EOFLOGObjectFnStop(); + + return entity; +} + +- (EOEntity*)entityForClass: (Class)classObject +{ + EOModelGroup *modelGroup; + NSArray *models; + EOModel *model; + int modelCount; + NSArray *entities; + EOEntity *entity; + NSString *className; + NSString *entityClassName; + int i, j, entityCount; + EOEntity *result = nil; + BOOL matchesClassName; + + EOFLOGObjectFnStartOrCond(@"EOEditingContext"); + + className = NSStringFromClass(classObject); + + modelGroup = [self modelGroup]; + models = [modelGroup models]; + modelCount = [models count]; + + for (i = 0 ; i < modelCount ; i++) + { + model = [models objectAtIndex: i]; + entities = [model entities]; + entityCount = [entities count]; + + for (j = 0 ; j < entityCount ; j++) + { + entity = [entities objectAtIndex: j]; + entityClassName = [entity className]; + matchesClassName = [className isEqualToString: entityClassName]; + + // Java class names in the Objective-C run-time system use '/' instead of '.' to separate package names, so we also check for a class name in which we replaced '.' with '/'. + + if (!matchesClassName + && ([entityClassName rangeOfString:@"."].length != 0)) + matchesClassName = [className + isEqualToString: + [[entityClassName componentsSeparatedByString: @"."] + componentsJoinedByString: @"/"]]; + + if (matchesClassName) + { + if (result) + [NSException raise: EOMoreThanOneException + format: @"%@ found more than one entity for class named %@", + NSStringFromSelector(_cmd), + className]; + else + result = entity; + } + } + } + + if (!result) + [NSException raise: /*NSObjectNotAvailableException*/NSInvalidArgumentException + format: @"%@ could not find entity for class named %@", + NSStringFromSelector(_cmd), className]; + + EOFLOGObjectFnStopOrCond(@"EOEditingContext"); + + return result; +} + +- (EOEntity*)entityForObject: (id)object +{ + EOClassDescription *classDesc; + EOEntity *newEntity; + + EOFLOGObjectFnStartOrCond(@"EOEditingContext"); + + classDesc = [object classDescription]; + + if ([classDesc isKindOfClass: [EOEntityClassDescription class]] == NO) + [NSException raise: NSInvalidArgumentException + format: @"%@ - %@: the object's class description must be an EOEntityClassDescription", + NSStringFromSelector(_cmd), + object]; + + newEntity = [(EOEntityClassDescription *)classDesc entity]; + + EOFLOGObjectFnStopOrCond(@"EOEditingContext"); + + return newEntity; +} + +@end diff --git a/EOAccess/GNUmakefile b/EOAccess/GNUmakefile new file mode 100644 index 0000000..9e8ff3e --- /dev/null +++ b/EOAccess/GNUmakefile @@ -0,0 +1,123 @@ +# +# EOAccess makefile for GNUstep Database Library. +# +# Copyright (C) 2000-2002 Free Software Foundation, Inc. +# +# Author: Mirko Viviani +# +# This file is part of the GNUstep Database Library. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +# Install into the system root by default +GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_SYSTEM_ROOT) + +GNUSTEP_MAKEFILES = $(GNUSTEP_SYSTEM_ROOT)/Makefiles + +include $(GNUSTEP_MAKEFILES)/common.make + +include ../Version + +# The library to be compiled +LIBRARY_NAME=libgnustep-db2 + +LIBRARIES_DEPEND_UPON=-lgnustep-base -lFoundationExt -lgnustep-db2control + +# The C source files to be compiled +libgnustep-db2_C_FILES = + +# The Objective-C source files to be compiled +libgnustep-db2_OBJC_FILES = \ +EOModelGroup.m \ +EOModel.m \ +EOEntity.m \ +EOAttribute.m \ +EORelationship.m \ +EOJoin.m \ +EOStoredProcedure.m \ +EOExpressionArray.m \ +EOAdaptor.m \ +EOAdaptorContext.m \ +EOAdaptorChannel.m \ +EOAdaptorOperation.m \ +EODatabaseOperation.m \ +EOSQLExpression.m \ +EOSQLQualifier.m \ +EODatabase.m \ +EODatabaseChannel.m \ +EODatabaseContext.m \ +EOAccessFault.m \ +EODatabaseDataSource.m \ +EOUtilities.m + +libgnustep-db2_HEADER_FILES_DIR = . +libgnustep-db2_HEADER_FILES_INSTALL_DIR = /EOAccess + +libgnustep-db2_HEADER_FILES = \ +EOModelGroup.h \ +EOModel.h \ +EOEntity.h \ +EOAttribute.h \ +EORelationship.h \ +EOJoin.h \ +EOStoredProcedure.h \ +EOAdaptor.h \ +EOAdaptorContext.h \ +EOAdaptorChannel.h \ +EODatabaseOperation.h \ +EOSQLExpression.h \ +EOSQLQualifier.h \ +EODatabase.h \ +EODatabaseChannel.h \ +EODatabaseContext.h \ +EOAccessFault.h \ +EOPropertyListEncoding.h \ +EODatabaseDataSource.h \ +EOSchemaGeneration.h \ +EOUtilities.h \ +EOAccess.h + +gdl2_AUTOGSDOC_HEADERS = $(libgnustep-db2_HEADER_FILES) +gdl2_AUTOGSDOC_SOURCE = $(libgnustep-db2_OBJC_FILES) +DOCUMENT_NAME = gdl2 +gdl2_HEADER_FILES_DIR = $(HEADER_DIR) +gdl2_AGSDOC_FILES = gdl2.gsdoc $(gdl2_AUTOGSDOC_HEADERS) +#$(gdl2_AUTOGSDOC_SOURCE) +gdl2_AGSDOC_FLAGS = \ + -Declared EOAccess \ + -Standards YES \ + -Project gdl2 \ + -WordMap '{\ + FOUNDATION_EXPORT=extern;FOUNDATION_STATIC_INLINE="";\ + GS_GEOM_SCOPE=extern;GS_GEOM_ATTR="";\ + GS_EXPORT=extern;GS_DECLARE="";\ + GS_RANGE_SCOPE=extern;GS_RANGE_ATTR="";\ + GS_ZONE_SCOPE=extern;GS_ZONE_ATTR="";\ + }' -Up gdl2 + + +-include Makefile.preamble + +-include GNUmakefile.local + +include $(GNUSTEP_MAKEFILES)/library.make +# Only build the doc if doc=yes was passed on the command line +ifeq ($(doc),yes) +include $(GNUSTEP_MAKEFILES)/documentation.make +endif + + +-include Makefile.postamble diff --git a/EOAccess/Makefile.postamble b/EOAccess/Makefile.postamble new file mode 100644 index 0000000..0af2e0c --- /dev/null +++ b/EOAccess/Makefile.postamble @@ -0,0 +1,69 @@ +# +# Makefile.postamble +# +# Copyright (C) 1997 Free Software Foundation, Inc. +# +# Written by: Scott Christley +# +# This file is part of the GNUstep Database Library. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +# +# Makefile.postamble +# +# Project specific makefile rules +# +# Uncomment the targets you want. +# The double colons (::) are important, do not make them single colons +# otherwise the normal makefile rules will not be performed. +# + +# Things to do before compiling +before-all:: + +# Things to do after compiling +# after-all:: + +# Things to do before installing +# before-install:: + +# Things to do after installing +# after-install:: + +# Things to do before uninstalling +# before-uninstall:: + +# Things to do after uninstalling +# after-uninstall:: + +# Things to do before cleaning +# before-clean:: + +# Things to do after cleaning +# after-clean:: + +# Things to do before distcleaning +# before-distclean:: + +# Things to do after distcleaning +# after-distclean:: + +# Things to do before checking +# before-check:: + +# Things to do after checking +# after-check: diff --git a/EOAccess/Makefile.preamble b/EOAccess/Makefile.preamble new file mode 100644 index 0000000..87e3095 --- /dev/null +++ b/EOAccess/Makefile.preamble @@ -0,0 +1,72 @@ +# +# Makefile.preamble +# +# Copyright (C) 1997 Free Software Foundation, Inc. +# +# Written by: Scott Christley +# +# This file is part of the GNUstep Database Library. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +# +# Makefile.preamble +# +# Project specific makefile variables, and additional +# +# Do not put any Makefile rules in this file, instead they should +# be put into Makefile.postamble. +# + +# +# Flags dealing with compiling and linking +# + +# Additional flags to pass to the preprocessor +ADDITIONAL_CPPFLAGS = $(FND_DEFINE) $(RUNTIME_DEFINE) -g + +# Additional flags to pass to the Objective-C compiler +ADDITIONAL_OBJCFLAGS = + +# Additional flags to pass to the C compiler +ADDITIONAL_CFLAGS = + +# Additional include directories the compiler should search +ADDITIONAL_INCLUDE_DIRS = -I.. + +# Additional LDFLAGS to pass to the linker +ADDITIONAL_LDFLAGS = + +# Additional library directories the linker should search +ADDITIONAL_LIB_DIRS = + +# +# Flags dealing with installing and uninstalling +# + +# Additional directories to be created during installation +ADDITIONAL_INSTALL_DIRS = + + +# What are the libraries this library depends upon. This is needed for some +# systems where building a shared library requires to pass to the linker +# all the libraries the target library depends upon. + +LIBRARIES_DEPEND_UPON = -l$(FOUNDATION_LIBRARY_NAME) + +ifeq ($(FOUNDATION_HAS_KVC), yes) + ADDITIONAL_OBJCFLAGS := $(ADDITIONAL_OBJCFLAGS) -DFOUNDATION_HAS_KVC=1 +endif diff --git a/EOAccess/gdl2.gsdoc b/EOAccess/gdl2.gsdoc new file mode 100644 index 0000000..53782df --- /dev/null +++ b/EOAccess/gdl2.gsdoc @@ -0,0 +1,23 @@ + + + + + GDL2 + + + + + + + + + + GDL2 +

... +

+
+ + + + +
diff --git a/EOAdaptors/GNUmakefile.in b/EOAdaptors/GNUmakefile.in new file mode 100644 index 0000000..d7edab9 --- /dev/null +++ b/EOAdaptors/GNUmakefile.in @@ -0,0 +1,40 @@ +# +# EOAdaptors makefile for GNUstep Database Library. +# +# Copyright (C) 2002 Free Software Foundation, Inc. +# +# Written by: Mirko Viviani +# +# This file is part of the GNUstep Database Library. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +GNUSTEP_MAKEFILES = $(GNUSTEP_SYSTEM_ROOT)/Makefiles + +include $(GNUSTEP_MAKEFILES)/common.make + +include ../Version + +# +# The list of subproject directories +# +SUBPROJECTS = @EOADAPTORS@ + +-include Makefile.preamble + +include $(GNUSTEP_MAKEFILES)/aggregate.make + +-include Makefile.postamble diff --git a/EOAdaptors/Postgres95/GNUmakefile.in b/EOAdaptors/Postgres95/GNUmakefile.in new file mode 100644 index 0000000..46dee59 --- /dev/null +++ b/EOAdaptors/Postgres95/GNUmakefile.in @@ -0,0 +1,91 @@ +# +# PostgreSQL makefile for GNUstep Database Library. +# +# Copyright (C) 2000-2002 Free Software Foundation, Inc. +# +# Author: Mirko Viviani +# +# This file is part of the GNUstep Database Library. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +GNUSTEP_MAKEFILES = $(GNUSTEP_SYSTEM_ROOT)/Makefiles + +include $(GNUSTEP_MAKEFILES)/common.make + +include ../../Version + +POSTGRES95_DATABASE=@POSTGRES_DATABASE@ + +# The framework to be compiled +FRAMEWORK_NAME=Postgres95EOAdaptor + +# Install into the local root by default +Postgres95EOAdaptor_INSTALLATION_DIR = $(GNUSTEP_LOCAL_ROOT) + +# The framework principal class +Postgres95EOAdaptor_PRINCIPAL_CLASS = Postgres95Adaptor + +# The framework Objective-C source files to be compiled +Postgres95EOAdaptor_OBJC_FILES = \ +Postgres95Adaptor.m \ +Postgres95Context.m \ +Postgres95Channel.m \ +Postgres95SQLExpression.m \ +Postgres95Values.m + +Postgres95EOAdaptor_HEADER_FILES = \ +Postgres95Adaptor.h \ +Postgres95Context.h \ +Postgres95Channel.h \ +Postgres95SQLExpression.h \ +Postgres95Values.h + + +Postgres95EOAdaptor_AUTOGSDOC_HEADERS = $(Postgres95EOAdaptor_HEADER_FILES) +Postgres95EOAdaptor_AUTOGSDOC_SOURCE = $(Postgres95EOAdaptor_OBJC_FILES) +DOCUMENT_NAME = Postgres95EOAdaptor +Postgres95EOAdaptor_AGSDOC_FILES = Postgres95EOAdaptor.gsdoc $(Postgres95EOAdaptor_AUTOGSDOC_HEADERS) +#$(Postgres95EOAdaptor_AUTOGSDOC_SOURCE) +Postgres95EOAdaptor_AGSDOC_FLAGS = \ + -Declared Foundation \ + -Standards YES \ + -SystemProjects System \ + -Project Postgres95EOAdaptor \ + -WordMap '{\ + FOUNDATION_EXPORT=extern;FOUNDATION_STATIC_INLINE="";\ + GS_GEOM_SCOPE=extern;GS_GEOM_ATTR="";\ + GS_EXPORT=extern;GS_DECLARE="";\ + GS_RANGE_SCOPE=extern;GS_RANGE_ATTR="";\ + GS_ZONE_SCOPE=extern;GS_ZONE_ATTR="";\ + }' -Up Postgres95EOAdaptor + + +-include Makefile.preamble + +-include GNUmakefile.local + +ifeq ($(POSTGRES95_DATABASE),yes) +include $(GNUSTEP_MAKEFILES)/framework.make +else +include $(GNUSTEP_MAKEFILES)/rules.make +endif +# Only build the doc if doc=yes was passed on the command line +ifeq ($(doc),yes) +include $(GNUSTEP_MAKEFILES)/documentation.make +endif + +-include Makefile.postamble diff --git a/EOAdaptors/Postgres95/Info.plist b/EOAdaptors/Postgres95/Info.plist new file mode 100644 index 0000000..7162eac --- /dev/null +++ b/EOAdaptors/Postgres95/Info.plist @@ -0,0 +1,4 @@ +{ + NSPrincipalClass = Postgres95Adaptor; + NSExecutable = Postgres95; +} diff --git a/EOAdaptors/Postgres95/Makefile.preamble b/EOAdaptors/Postgres95/Makefile.preamble new file mode 100644 index 0000000..32caad2 --- /dev/null +++ b/EOAdaptors/Postgres95/Makefile.preamble @@ -0,0 +1,61 @@ +# +# Makefile.preamble +# +# Copyright (C) 2000-2002 Free Software Foundation, Inc. +# +# Author: Mirko Viviani +# +# This file is part of the GNUstep Database Library. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +# +# Makefile.preamble +# +# Project specific makefile variables, and additional +# +# Do not put any Makefile rules in this file, instead they should +# be put into Makefile.postamble. +# + +# +# Flags dealing with compiling and linking +# + +# Additional flags to pass to the preprocessor +ADDITIONAL_CPPFLAGS = + +# Additional flags to pass to the Objective-C compiler +ADDITIONAL_OBJCFLAGS = + +# Additional flags to pass to the C compiler +ADDITIONAL_CFLAGS = + +# Additional include directories the compiler should search +ADDITIONAL_INCLUDE_DIRS = -I../.. -I/usr/local/pgsql/include + +# Additional LDFLAGS to pass to the linker +ADDITIONAL_LDFLAGS = -lpq + +# Additional library directories the linker should search +ADDITIONAL_LIB_DIRS = -L/usr/local/pgsql/lib + +# +# Flags dealing with installing and uninstalling +# + +# Additional directories to be created during installation +ADDITIONAL_INSTALL_DIRS = diff --git a/EOAdaptors/Postgres95/Makefile.preamble.in b/EOAdaptors/Postgres95/Makefile.preamble.in new file mode 100644 index 0000000..3348d39 --- /dev/null +++ b/EOAdaptors/Postgres95/Makefile.preamble.in @@ -0,0 +1,61 @@ +# +# Makefile.preamble +# +# Copyright (C) 2000-2002 Free Software Foundation, Inc. +# +# Author: Mirko Viviani +# +# This file is part of the GNUstep Database Library. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +# +# Makefile.preamble +# +# Project specific makefile variables, and additional +# +# Do not put any Makefile rules in this file, instead they should +# be put into Makefile.postamble. +# + +# +# Flags dealing with compiling and linking +# + +# Additional flags to pass to the preprocessor +ADDITIONAL_CPPFLAGS = + +# Additional flags to pass to the Objective-C compiler +ADDITIONAL_OBJCFLAGS = + +# Additional flags to pass to the C compiler +ADDITIONAL_CFLAGS = + +# Additional include directories the compiler should search +ADDITIONAL_INCLUDE_DIRS = -I../.. @POSTGRES_INCLUDES@ + +# Additional LDFLAGS to pass to the linker +ADDITIONAL_LDFLAGS = @POSTGRES_LIBS@ + +# Additional library directories the linker should search +ADDITIONAL_LIB_DIRS = @POSTGRES_LIB_DIRS@ + +# +# Flags dealing with installing and uninstalling +# + +# Additional directories to be created during installation +ADDITIONAL_INSTALL_DIRS = diff --git a/EOAdaptors/Postgres95/Postgres95Adaptor.h b/EOAdaptors/Postgres95/Postgres95Adaptor.h new file mode 100644 index 0000000..2cc5f43 --- /dev/null +++ b/EOAdaptors/Postgres95/Postgres95Adaptor.h @@ -0,0 +1,104 @@ +/* + Postgres95Adaptor.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __Postgres95Adaptor_h__ +#define __Postgres95Adaptor_h__ + +#import + + +/* Include Postgres 95 Headers */ + +#undef Assert +#include +#include +#include +#undef Assert + +@class NSMutableArray; +@class NSMutableSet; + +/* The following keys are meaningful in the connectionDictionary in a model: + + databaseServer or hostName - the name of the server + (default getenv(PGHOST) or localhost) + databaseName - the name of the database to use + (default getenv(PGDATABASE)) + options - additional options sent to the POSTGRES95 backend + (default getenv(PGOPTIONS)) + port - port to communicate with POSTGRES95 backend + (default getenv(PGPORT)) + debugTTY - filename (file/device) used for debugging output + (default getenv(PGTTY)) + primaryKeySequenceNameFormat - Format for pk sequence name; + like @"%@_SEQ" or @"EOSEQ_%@", "%@" is replaced by external table name + (default: @"%@_SEQ") + NOTE: user name is not given explicitly - the library uses the + real user id of the user running the program and that user id + is interpreted by the server (AFAIK) +*/ + +@interface Postgres95Adaptor : EOAdaptor +{ + NSMutableArray *_pgConnPool; + int _pgConnPoolLimit; + NSString* _primaryKeySequenceNameFormat; + struct { + BOOL cachePGconn:1; + } _flags; +} + +/* Reporting errors */ +- (void)privateReportError: (PGconn *)pgConn; + +/* Configure the adaptor to share the PGconn or not. The default is not to + share PGconn. */ +- (void)setCachePGconn: (BOOL)flag; +- (BOOL)cachePGconn; +- (void)setPGconnPoolLimit: (int)newLimit; +- (int)pgConnPoolLimit; + +/* Inherited methods */ + +// Private methods + +/* Obtaining and releasing a PGconn from pool */ +- (PGconn *)createPGconn; +- (PGconn *)newPGconn; +- (void)releasePGconn: (PGconn *)pgConn force: (BOOL)flag; + +// format is something like @"%@_SEQ" or @"EOSEQ_%@", "%@" is replaced by external table name +- (void)setPrimaryKeySequenceNameFormat: (NSString*)format; +- (NSString*)primaryKeySequenceNameFormat; + +extern NSString *Postgres95Exception; + +@end + +#endif /* __Postgres95Adaptor_h__ */ diff --git a/EOAdaptors/Postgres95/Postgres95Adaptor.m b/EOAdaptors/Postgres95/Postgres95Adaptor.m new file mode 100644 index 0000000..03bb67e --- /dev/null +++ b/EOAdaptors/Postgres95/Postgres95Adaptor.m @@ -0,0 +1,489 @@ +/** + Postgres95Adaptor.m Postgres95Adaptor + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + based on the Postgres95 adaptor written by + Mircea Oancea + + Author: Manuel Guesdon + Date: October 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import +#import +#import +#import +#import +#import +#import + +#import + +#import +#import +#import +#import +#import + +#import +#import +#import +#import +#import + + +NSString *Postgres95Exception = @"Postgres95Exception"; +static int pgConnTotalAllocated = 0; +static int pgConnCurrentAllocated = 0; + + +@implementation Postgres95Adaptor + +- init +{ + return [self initWithName: @"Postgres95"]; +} + +- initWithName: (NSString *)name +{ + if ((self = [super initWithName: name])) + { + _pgConnPool = [NSMutableArray new]; + } + + return self; +} + +- (void)dealloc +{ + NSEnumerator *enumerator; + PGconn *pgConn; + + enumerator = [_pgConnPool objectEnumerator]; + + while ((pgConn = [[enumerator nextObject] pointerValue])) + [self releasePGconn: pgConn force: YES]; + + [_pgConnPool release]; + + [super dealloc]; +} + +- (void)privateReportError: (PGconn*)pgConn +{ + char *message = "NULL pgConn in privateReportError:"; + + EOFLOGObjectFnStart(); + + if (pgConn) + message = PQerrorMessage(pgConn); + + NSLog(@"%s", message); + + EOFLOGObjectFnStop(); +} + +- (void)setCachePGconn: (BOOL)flag +{ + _flags.cachePGconn = flag; +} + +- (BOOL)cachePGconn +{ + return _flags.cachePGconn; +} + +- (void)setPGconnPoolLimit: (int)value +{ + _pgConnPoolLimit = value; +} + +- (int)pgConnPoolLimit +{ + return _pgConnPoolLimit; +} + +/*+ (NSDictionary *)defaultConnectionDictionary +{ + static NSDictionary *dict = nil; + + if (!dict) + dict = [[NSDictionary dictionaryWithObjectsAndKeys:NSHomeDirectory(), FlatFilePathKey, [self defaultRowSeparator], FlatFileRowSeparatorKey, [self defaultColumnSeparator], FlatFileColumnSeparatorKey, @"Y", FlatFileUseHeadersKey, nil] retain]; + + return dict; + }*/ + +static NSString *externalTypeNames[] = { + @"bool", + @"char", @"char2", @"char4", @"char8", @"char16", @"filename", + @"date", @"reltime", @"time", @"tinterval", @"abstime", + @"float4", @"float8", + @"int4", @"int2", + @"oid", @"oid8", @"oidint2", @"oidint4", @"oidchar16", + @"varchar", @"bpchar", + @"cid", @"tid", @"xid", + nil +}; + +static NSString *internalTypeNames[] = { + @"NSNumber", + @"NSNumber", @"NSNumber", @"NSNumber", @"NSNumber", @"NSNumber", @"NSNumber", + @"NSCalendarDate", @"NSCalendarDate", @"NSCalendarDate", @"NSCalendarDate", @"NSCalendarDate", + @"NSNumber", @"NSNumber", + @"NSNumber", @"NSNumber", + @"NSNumber", @"NSNumber", @"NSNumber", @"NSNumber", @"NSNumber", + @"NSString", @"NSString", + @"NSDecimalNumber", @"NSDecimalNumber", @"NSDecimalNumber", + nil +}; + ++ (NSDictionary *)externalToInternalTypeMap +{ + static NSDictionary *externalToInternalTypeMap = nil; + + if (!externalToInternalTypeMap) + { + int i; + + for (i = 0; externalTypeNames[i]; i++); + + externalToInternalTypeMap = [[NSDictionary dictionaryWithObjects: internalTypeNames forKeys: externalTypeNames count: i] retain]; + } + + return externalToInternalTypeMap; +} + ++ (NSString *)internalTypeForExternalType: (NSString *)extType + model: (EOModel *)model +{ + return [[self externalToInternalTypeMap] objectForKey: extType]; +} + ++ (NSArray *)externalTypesWithModel:(EOModel *)model +{ + return [[self externalToInternalTypeMap] allKeys]; +} + ++ (void)assignExternalInfoForAttribute: (EOAttribute *)attribute +{ + // TODO + EOAdaptorValueType value = [attribute adaptorValueType]; + + [attribute setExternalType: externalTypeNames[value]]; +} + ++ (void)assignExternalInfoForEntity: (EOEntity *)entity +{ + NSEnumerator *attributeEnumerator = [[entity attributes] objectEnumerator]; + EOAttribute *attribute; + + while ((attribute = [attributeEnumerator nextObject])) + [self assignExternalInfoForAttribute: attribute]; +} + +/* Inherited methods */ + +- (EOAdaptorContext *)createAdaptorContext +{ + //OK + return [Postgres95Context adaptorContextWithAdaptor: self]; +} + +- (Class)defaultExpressionClass +{ + Class expressionClass; + + EOFLOGObjectFnStart(); + + expressionClass = [Postgres95SQLExpression class]; + + EOFLOGObjectFnStop(); + + return expressionClass; +} + +- (BOOL)isValidQualifierType: (NSString *)typeName + model: (EOModel *)model +{ + int i; + + for (i = 0; externalTypeNames[i]; i++) + { + //TODO REMOVE + NSDebugMLog(@"externalTypeNames[i]=%@", externalTypeNames[i]); + + if ([externalTypeNames[i] isEqualToString: typeName]) + return YES; + } + //TODO REMOVE + + NSDebugMLog(@"typeName=%@", typeName); + + return NO; +} + +- (void)assertConnectionDictionaryIsValid +{ + NSException *exception = nil; + EOAdaptorContext *adaptorContext; + EOAdaptorChannel *adaptorChannel; + + if (![self hasOpenChannels]) + { + adaptorContext = [self createAdaptorContext]; + adaptorChannel = [adaptorContext createAdaptorChannel]; + + NS_DURING + [adaptorChannel openChannel]; + NS_HANDLER + exception = localException; + NS_ENDHANDLER; + + [adaptorChannel closeChannel]; + + if (exception) + [exception raise]; + } +} + +/* +-(NSString *)formatValue:(id)value + forAttribute:(EOAttribute*)attribute +{ + return [value stringValueForPostgres95Type:[attribute externalType] + attribute:attribute]; +} +*/ + +- (NSString *)fetchedValueForString: (NSString *)value + attribute: (EOAttribute *)attribute +{ + return value; +} + + +//TODO: don't need to be overriden ?? +- (NSNumber *)fetchedValueForNumberValue: (NSNumber *)value + attribute: (EOAttribute *)attribute +{ + return value; // TODO scale and precision +} + +- (NSCalendarDate *)fetchedValueForDateValue: (NSCalendarDate *)value + attribute: (EOAttribute *)attribute +{ + return value; +} + +- (NSData *)fetchedValueForDataValue: (NSData *)value + attribute: (EOAttribute *)attribute +{ + return value; +} + +- (void)createDatabaseWithAdministrativeConnectionDictionary: (NSDictionary *)connectionDictionary +{ +} + +- (void)dropDatabaseWithAdministrativeConnectionDictionary: (NSDictionary *)connectionDictionary +{ +} + +/* Private methods for Postgres Adaptor */ + +- (PGconn *)createPGconn +{ + char *pg_host = NULL; + char *pg_database = NULL; + char *pg_port = NULL; + char *pg_options = NULL; + char *pg_tty = NULL; + char *pg_user = NULL; + char *pg_pwd = NULL; + PGconn *pgConn = NULL; + PGresult *pgResult = NULL; + NSString *str = nil; + + EOFLOGObjectFnStart(); + + //OK + str = [_connectionDictionary objectForKey: @"databaseServer"]; + if (!str) + str = [_connectionDictionary objectForKey: @"hostName"]; + + pg_host = (char*)[str cString]; + + pg_database = (char*)[[_connectionDictionary objectForKey: @"databaseName"] + cString]; + pg_port = (char*)[[_connectionDictionary objectForKey: @"port"] cString]; + if (!pg_port) + pg_port = (char*)[[_connectionDictionary objectForKey: @"hostPort"] + cString]; + + pg_options = (char*)[[_connectionDictionary objectForKey: @"options"] + cString]; + pg_tty = (char*)[[_connectionDictionary objectForKey: @"debugTTY"] cString]; + pg_user = (char*)[[_connectionDictionary objectForKey: @"userName"] + cString]; + pg_pwd = (char*)[[_connectionDictionary objectForKey: @"password"] + cString]; + + NSLog(@"%s %s %s %s %s", pg_host, pg_port, pg_database, pg_user, pg_pwd); + NSDebugMLog(@"%s %s %s %s %s", pg_host, pg_port, pg_database, pg_user, pg_pwd); + + // Try to connect to the Postgres95 server + if (pg_user) + pgConn = PQsetdbLogin(pg_host, pg_port, pg_options, pg_tty, + pg_database,pg_user,pg_pwd); + else + pgConn = PQsetdb(pg_host, pg_port, pg_options, pg_tty, pg_database); + + NSDebugMLog(@"%s %s %s %s %s", pg_host, pg_port, pg_database, pg_user, + pg_pwd); + + // Check connection + if (PQstatus(pgConn) == CONNECTION_BAD) + { + //TODO: report error in an exception ? + [self privateReportError: pgConn]; + PQfinish(pgConn); + pgConn = NULL; + } + + if (pgConn) + { + pgResult = PQexec(pgConn, "SET DATESTYLE TO 'SQL'"); + PQclear(pgResult); + pgResult = NULL; + + if (pgConn) + { + pgConnTotalAllocated++; + pgConnCurrentAllocated++; + } + } + + EOFLOGObjectFnStop(); + + return pgConn; +} + +- (PGconn *)newPGconn +{ + PGconn *pgConn = NULL; + + if(_flags.cachePGconn && [_pgConnPool count]) + { + NSDebugMLog(@"newPGconn cached %p (pgConn=%p) total=%d current=%d", + self, + pgConn, + pgConnTotalAllocated, + pgConnCurrentAllocated); + + pgConn = [[_pgConnPool lastObject] pointerValue]; + [_pgConnPool removeLastObject]; + } + else + { + pgConn = [self createPGconn]; + + NSDebugMLog(@"newPGconn not cached %p (pgConn=%p) total=%d current=%d", + self, + pgConn, + pgConnTotalAllocated, + pgConnCurrentAllocated); + } + + return pgConn; +} + +- (void)releasePGconn: (PGconn *)pgConn + force: (BOOL)flag +{ + if (!flag + && _flags.cachePGconn + && (PQstatus(pgConn) == CONNECTION_OK) + && [_pgConnPool count] < _pgConnPoolLimit) + { + NSDebugMLog(@"releasePGconn -> in pool %p (pgConn=%p) total=%d current=%d", + self, + pgConn, + pgConnTotalAllocated, + pgConnCurrentAllocated); + + [_pgConnPool addObject: [NSValue value: pgConn + withObjCType: @encode(PGconn*)]]; + } + else + { + NSDebugMLog(@"releasePGconn really %p (pgConn=%p) total=%d current=%d", + self, + pgConn, + pgConnTotalAllocated, + pgConnCurrentAllocated); + + pgConnCurrentAllocated--; + PQfinish(pgConn); + } +} + +// format is something like @"%@_SEQ" or @"EOSEQ_%@", "%@" is replaced by external table name +- (void)setPrimaryKeySequenceNameFormat: (NSString*)format +{ + ASSIGN(_primaryKeySequenceNameFormat, format); +} + +- (NSString*)primaryKeySequenceNameFormat +{ + if (!_primaryKeySequenceNameFormat) + _primaryKeySequenceNameFormat = [_connectionDictionary objectForKey: @"primaryKeySequenceNameFormat"]; + + if (!_primaryKeySequenceNameFormat) + _primaryKeySequenceNameFormat = @"%@_SEQ"; + + return _primaryKeySequenceNameFormat; +} + +@end /* Postgres95Adaptor */ + +/* +//TODO +databaseEncoding +{ + self connectionDictionary +call dict obj for key databaseEncoding + return 2 par defaut +}; +*/ + diff --git a/EOAdaptors/Postgres95/Postgres95Channel.h b/EOAdaptors/Postgres95/Postgres95Channel.h new file mode 100644 index 0000000..6054c36 --- /dev/null +++ b/EOAdaptors/Postgres95/Postgres95Channel.h @@ -0,0 +1,89 @@ +/* + Postgres95Channel.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + based on the Postgres95 adaptor written by + Mircea Oancea + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __Postgres95Channel_h__ +#define __Postgres95Channel_h__ + +#import +#import + + +@class NSMutableDictionary; +@class NSMutableArray; +@class EOAttribute; + +@interface Postgres95Channel : EOAdaptorChannel +{ + Postgres95Context *_adaptorContext; + PGconn *_pgConn; + PGresult *_pgResult; + NSArray *_attributes; + NSArray *_origAttributes; + EOSQLExpression *_sqlExpression; + int _currentResultRow; + NSMutableDictionary *_oidToTypeName; + BOOL _isFetchInProgress; + BOOL _fetchBlobsOid; + NSArray *_pkAttributeArray; + + struct { + unsigned int postgres95InsertedRowOid:1; + unsigned int postgres95Notification:1; + } _postgres95DelegateRespondsTo; +} + +- (PGconn*)pgConn; +- (PGresult*)pgResult; +- (BOOL)advanceRow; +- (void)cleanupFetch; + +- (void)_cancelResults; +- (void)_describeResults; + +/* Private methods */ +- (char*)_readBinaryDataRow: (Oid)oid length: (int*)length zone: (NSZone*)zone; +- (Oid)_insertBinaryData: (NSData*)binaryData forAttribute: (EOAttribute*)attr; +- (Oid)_updateBinaryDataRow: (Oid)oid data: (NSData*)binaryData; +- (void)_describeDatabaseTypes; + +- (BOOL)_evaluateExpression: (EOSQLExpression *)expression + withAttributes: attrs; + +@end + +@interface NSObject (Postgres95ChannelDelegate) + +- (void)postgres95Channel: (Postgres95Channel*)channel + insertedRowWithOid: (Oid)oid; +- (void)postgres95Channel: (Postgres95Channel*)channel + receivedNotification: (NSString*)notification; + +@end + +#endif /* __Postgres95Channel_h__ */ diff --git a/EOAdaptors/Postgres95/Postgres95Channel.m b/EOAdaptors/Postgres95/Postgres95Channel.m new file mode 100644 index 0000000..5824eed --- /dev/null +++ b/EOAdaptors/Postgres95/Postgres95Channel.m @@ -0,0 +1,1451 @@ +/** + Postgres95Channel.m Postgres95Channel + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + based on the Postgres95 adaptor written by + Mircea Oancea + + Author: Manuel Guesdon + Date: October 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import +#import +#import +#import + +#import +#import + +#import + +#import +#import + +#import +#import +#import + + +static void __dummy_function_used_for_linking(void) +{ + extern void __postgres95_values_linking_function(void); + + __postgres95_values_linking_function(); + __dummy_function_used_for_linking(); +} + +@implementation Postgres95Channel + +- (id) initWithAdaptorContext: (EOAdaptorContext *)adaptorContext +{ + if ((self = [super initWithAdaptorContext: adaptorContext])) + { + EOAttribute *attr = nil; + + ASSIGN(_adaptorContext, adaptorContext);//TODO NO + +//verify + _oidToTypeName = [[NSMutableDictionary alloc] initWithCapacity: 101]; + + attr = [[[EOAttribute alloc] init] autorelease]; + [attr setName: @"nextval"]; + [attr setColumnName: @"nextval"]; + [attr setValueType: @"i"]; + [attr setValueClassName: @"NSNumber"]; + + ASSIGN(_pkAttributeArray, [NSArray arrayWithObject: attr]); + } + + return self; +} + +- (void)dealloc +{ + if ([self isOpen]) + [self closeChannel]; + + DESTROY(_adaptorContext); + DESTROY(_sqlExpression); + DESTROY(_oidToTypeName); + DESTROY(_pkAttributeArray); + + [super dealloc]; +} + +- (BOOL)isOpen +{ + return (_pgConn ? YES : NO); +} + +- (void)openChannel +{ + //OK + NSAssert(!_pgConn, @"Channel already opened"); + + _pgConn = [(Postgres95Adaptor *)[[self adaptorContext] adaptor] newPGconn]; + + if (_pgConn) + [self _describeDatabaseTypes]; +} + +- (void)closeChannel +{ + NSAssert(_pgConn, @"Channel not opened"); + + [self _cancelResults]; + [(Postgres95Adaptor *)[[self adaptorContext] adaptor] releasePGconn: _pgConn + force: NO]; + _pgConn = NULL; +} + +- (BOOL)isFetchInProgress +{ + return _isFetchInProgress; +} + +- (PGconn *)pgConn +{ + return _pgConn; +} + +- (PGresult *)pgResult +{ + return _pgResult; +} + +- (void)cancelFetch +{ + EOAdaptorContext *adaptorContext = nil; + + EOFLOGObjectFnStart(); + + adaptorContext = [self adaptorContext]; + [self cleanupFetch]; + +//NO ?? [self _cancelResults];//Done in cleanup fetch +// [_adaptorContext autoCommitTransaction];//Done in cleanup fetch + EOFLOGObjectFnStop(); +} + +- (void)_cancelResults +{ + EOFLOGObjectFnStart(); + + _fetchBlobsOid = NO; + + DESTROY(_attributes); + DESTROY(_origAttributes); + + if (_pgResult) + { + PQclear(_pgResult); + _pgResult = NULL; + _currentResultRow = -2; + } + + _isFetchInProgress = NO; + + EOFLOGObjectFnStop(); +} + +- (BOOL)advanceRow +{ + BOOL advanceRow = NO; + + // fetch results where read then freed + EOFLOGObjectFnStart(); + + if (_pgResult) + { + // next row + _currentResultRow++; + + // check if result set is finished + if (_currentResultRow >= PQntuples(_pgResult)) + { + [self _cancelResults]; + } + else + advanceRow = YES; + } + + EOFLOGObjectFnStop(); + + return advanceRow; +} + +- (NSArray*)lowLevelResultFieldNames: (PGresult*)res +{ + NSMutableArray *names = [NSMutableArray array]; + int nb = PQnfields(res); + int i; + + for (i = 0; i < nb; i++) + { + char *szName = PQfname(res,i); + NSString *name = [NSString stringWithCString: szName]; + + [names addObject: name]; + } + + return names; +} + +- (NSMutableDictionary *)fetchRowWithZone: (NSZone *)zone +{ +//TODO +/* +//self cleanupFetch quand plus de row !! +valueClassName...externaltype on each attr +self adaptorContext +context adaptor +adaptor databaseEncoding//2 + + +self dictionaryWithObjects:??? +forAttributes:_attributes +zone:zone +//end +*/ + NSMutableDictionary *dict = nil; + + EOFLOGObjectFnStart(); + + if (_delegateRespondsTo.willFetchRow) + [_delegate adaptorChannelWillFetchRow: self]; + + NSDebugMLLog(@"gsdb",@"[self isFetchInProgress]: %s", + ([self isFetchInProgress] ? "YES" : "NO")); + + if ([self isFetchInProgress]) + { + NSDebugMLLog(@"gsdb", @"ATTRIBUTES=%@", _attributes); + + if (!_attributes) + [self _describeResults]; + + if ([self advanceRow] == NO) + { + NSDebugMLLog(@"gsdb", @"No Advance Row"); + + // Return nil to indicate that the fetch operation was finished + if (_delegateRespondsTo.didFinishFetching) + [_delegate adaptorChannelDidFinishFetching: self]; + + [self _cancelResults]; + } + else + { + int i; + int count = [_attributes count]; + id valueBuffer[100]; + id *values = NULL; + EONull *nullValue = (EONull *)[EONull null]; + + NSDebugMLLog(@"gsdb", @"count=%d", count); + + if (count > PQnfields(_pgResult)) + { + NSDebugMLog(@"attempt to read %d attributes when the result set has only %d columns", + count, PQnfields(_pgResult)); + NSDebugMLog(@"_attributes=%@", _attributes); + NSDebugMLog(@"result=%@", [self lowLevelResultFieldNames: + _pgResult]); + [NSException raise: Postgres95Exception + format: @"attempt to read %d attributes " + @"when the result set has only %d columns", + count, PQnfields(_pgResult)]; + } + + if (count > 100) + values = (id *)NSZoneMalloc(zone, count * sizeof(id)); + else + values = valueBuffer; + + for (i = 0; i < count; i++) + { + EOAttribute *attr = [_attributes objectAtIndex: i]; + int length = 0; + const char *string = NULL; + + // If the column has the NULL value insert EONull in row + + if (PQgetisnull(_pgResult, _currentResultRow, i)) + { + values[i] = [nullValue retain]; //to be compatible with others returned values + } + else + { + string = PQgetvalue(_pgResult, _currentResultRow, i); + length = PQgetlength(_pgResult, _currentResultRow, i); + + // if external type for this attribute is "inversion" then this + // column represents an Oid of a large object + + if ([[attr externalType] isEqual: @"inversion"]) + { + if (!_fetchBlobsOid) + { + string = [self _readBinaryDataRow: (Oid)atol(string) + length:&length zone: zone]; + //For efficiency reasons, the returned value is NOT autoreleased ! + values[i] = [Postgres95Values newValueForBytes: string + length: length + attribute: attr]; + } + else + { + //For efficiency reasons, the returned value is NOT autoreleased ! + values[i] = [[NSNumber alloc] + initWithLong: atol(string)]; + } + } + else + { + //For efficiency reasons, the returned value is NOT autoreleased ! + values[i] = [Postgres95Values newValueForBytes: string + length: length + attribute: attr]; + } + } + + NSDebugMLLog(@"gsdb", @"value[%d]=%@", i, values[i]); + NSDebugMLog(@"TEST attributesToFetch=%@", [[attr entity] + attributesToFetch]); + } + + NSDebugMLLog(@"gsdb", @"values count=%d values=%p", count, values); + NSDebugMLLog(@"gsdb", @"_attributes=%@", _attributes); + + dict = [self dictionaryWithObjects: values + forAttributes: _attributes + zone: zone]; + + /* NO: For efficiency reasons, the returned value is NOT autoreleased ! + + for (i = 0; i < count; i++) + [values[i] release]; + */ + if (values != valueBuffer) + NSZoneFree(zone, values); + + if (_delegateRespondsTo.didFetchRow) + [_delegate adaptorChannel: self didFetchRow: dict]; + } + } + + NSDebugMLLog(@"gsdb", @"row: %@", dict); + + EOFLOGObjectFnStop(); + + return dict; //an EOMutableKnownKeyDictionary +} + +- (BOOL)_evaluateCommandsUntilAFetch +{ + BOOL ret = NO; + ExecStatusType status; + + EOFLOGObjectFnStart(); + + // Check results + status = PQresultStatus(_pgResult); + + NSDebugMLLog(@"gsdb",@"status=%d (%s)", + (int)status, + PQresStatus(status)); + + switch (status) + { + case PGRES_EMPTY_QUERY: + _isFetchInProgress = NO; + ret = YES; + break; + case PGRES_COMMAND_OK: + _isFetchInProgress = NO; + ret = YES; + break; + case PGRES_TUPLES_OK: + _isFetchInProgress = YES; + _currentResultRow = -1; + ret = YES; + break; + case PGRES_COPY_OUT: + _isFetchInProgress = NO; + ret = YES; + break; + case PGRES_COPY_IN: + _isFetchInProgress = NO; + ret = YES; + break; + case PGRES_BAD_RESPONSE: + case PGRES_NONFATAL_ERROR: + case PGRES_FATAL_ERROR: + { + if ([self isDebugEnabled]) + NSLog(@"SQL expression '%@' caused %s", + [_sqlExpression statement], PQerrorMessage(_pgConn)); + NSDebugMLLog(@"SQL expression '%@' caused %s", + [_sqlExpression statement], PQerrorMessage(_pgConn)); + [NSException raise: Postgres95Exception + format: @"unexpected result returned by PQresultStatus()"]; + + EOFLOGObjectFnStop(); + + return NO; + } + default: + { + [NSException raise: Postgres95Exception + format: @"unexpected result returned by PQresultStatus():"]; + break; + } + } + + NSDebugMLLog(@"gsdb", @"ret=%s", (ret ? "YES" : "NO")); + NSDebugMLLog(@"gsdb", @"_isFetchInProgress=%s", (_isFetchInProgress ? "YES" : "NO")); + + if (ret == YES) + { + PGnotify *notify = PQnotifies(_pgConn); + const char *insoid = NULL; + + if (notify) + { + if (_postgres95DelegateRespondsTo.postgres95Notification) + [_delegate postgres95Channel: self + receivedNotification: + [NSString stringWithCString: notify->relname]]; + + free(notify); + } + + insoid = PQoidStatus(_pgResult); + + if (*insoid && _postgres95DelegateRespondsTo.postgres95InsertedRowOid) + { + Oid oid = atol(insoid); + + [_delegate postgres95Channel: self insertedRowWithOid: oid]; + } + } + + NSDebugMLLog(@"gsdb",@"_isFetchInProgress=%s", + (_isFetchInProgress ? "YES" : "NO")); + + if ([self isFetchInProgress])// Mirko: TODO remove this ! + [self _describeResults]; + + if ([self isDebugEnabled]) + { + NSString *message = [NSString stringWithCString: PQcmdStatus(_pgResult)]; + + if (status == PGRES_TUPLES_OK) + message = [NSString stringWithFormat: + @"Command status %@. Returned %d rows with %d columns ", + message, PQntuples(_pgResult), PQnfields(_pgResult)]; + NSLog (@"Postgres95Adaptor: %@", message); + } + + NSDebugMLLog(@"gsdb", @"ret=%s", (ret ? "YES" : "NO")); + + EOFLOGObjectFnStop(); + + return ret; +} + +- (BOOL)_evaluateExpression: (EOSQLExpression *)expression + withAttributes: (NSArray*)attributes +{ + BOOL result = NO; + EOAdaptorContext *adaptorContext = nil; + + EOFLOGObjectFnStart(); + + NSDebugMLLog(@"gsdb", @"expression=%@", expression); + + ASSIGN(_sqlExpression, expression); + ASSIGN(_origAttributes, attributes); + +// NSDebugMLLog(@"gsdb",@"EE _origAttributes=%@",_origAttributes); +// NSDebugMLLog(@"gsdb",@"EE _attributes=%@",_attributes); + NSDebugMLLog(@"gsdb", @"Postgres95Adaptor: execute command:\n%@\n", + [expression statement]); + + if ([self isDebugEnabled] == YES) + NSLog(@"Postgres95Adaptor: execute command:\n%@\n", + [expression statement]); +//call PostgreSQLChannel numberOfAffectedRows + /* Send the expression to the SQL server */ + + _pgResult = PQexec(_pgConn, (char *)[[expression statement] cString]); + NSDebugMLLog(@"gsdb", @"_pgResult=%p", (void*)_pgResult); + + if (_pgResult == NULL) + { + if ([self isDebugEnabled]) + { + adaptorContext = [self adaptorContext]; + [(Postgres95Adaptor *)[adaptorContext adaptor] + privateReportError: _pgConn]; + } + } + else + { + /* Check command results */ + if ([self _evaluateCommandsUntilAFetch] != NO) + result = YES; + } + +//self numberOfAffectedRows + NSDebugMLLog(@"gsdb", @"result: %s", (result ? "YES" : "NO")); +// NSDebugMLLog(@"gsdb",@"FF attributes=%@",_attributes); + + EOFLOGObjectFnStop(); + + return result; +} + +- (void)evaluateExpression: (EOSQLExpression *)expression // OK quasi +{ + Postgres95Context *adaptorContext = nil; + + EOFLOGObjectFnStart(); + +//_evaluationIsDirectCalled=1 + adaptorContext = (Postgres95Context *)[self adaptorContext]; +//call expression statement +//call adaptorContext adaptor +//call adaptor databaseEncoding +//call self setErrorMessage +//call expre statement + + NSDebugMLLog(@"gsdb", @"expression=%@", expression); + + if (_delegateRespondsTo.shouldEvaluateExpression) + { + BOOL response + = [_delegate adaptorChannel: self + shouldEvaluateExpression: expression]; + + if (response == NO) + return; + } + + if ([self isOpen] == NO) + [NSException raise: Postgres95Exception + format: @"cannot execute SQL expression. Channel is not opened."]; + + [self _cancelResults]; + [adaptorContext autoBeginTransaction: NO/*YES*/]; //TODO: shouldbe yes ?? + + if (![self _evaluateExpression: expression + withAttributes: nil]) + { + NSDebugMLLog(@"gsdb", @"_evaluateExpression:withAttributes: return NO"); + [self _cancelResults]; + } + else + { + NSDebugMLLog(@"gsdb", @"expression=%@ [self isFetchInProgress]=%d", + expression, + [self isFetchInProgress]); + if (![self isFetchInProgress])//If a fetch is in progress, we don't want to commit because + //it will cancel fetch. I'm not sure it the 'good' way to do + [adaptorContext autoCommitTransaction]; + + if (_delegateRespondsTo.didEvaluateExpression) + [_delegate adaptorChannel: self didEvaluateExpression: expression]; + } + + EOFLOGObjectFnStop(); +} + +- (void)insertRow: (NSDictionary *)row + forEntity: (EOEntity *)entity +{ + EOSQLExpression *sqlexpr = nil; + NSMutableDictionary *nrow = nil; + NSEnumerator *enumerator = nil; + NSString *attrName = nil; + Postgres95Context *adaptorContext = nil; + + EOFLOGObjectFnStart(); + + NSDebugMLLog(@"gsdb", @"row=%@", row); + + if (![self isOpen]) + [NSException raise: NSInternalInconsistencyException + format: @"%@ -- %@ 0x%x: attempt to insert rows with no open channel", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + + if (!row || !entity) + [NSException raise: NSInvalidArgumentException + format: @"row and entity arguments for insertRow:forEntity:" + @" must not be nil objects"]; + + if ([self isFetchInProgress]) + [NSException raise: NSInternalInconsistencyException + format: @"%@ -- %@ 0x%x: attempt to insert rows with fetch in progress", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + + /* Before creating the SQL INSERT expression we have to replace in the + row the large objects as Oids and to insert them with the large + object file-like interface */ + + nrow = [[row mutableCopy] autorelease]; + + adaptorContext = (Postgres95Context *)[self adaptorContext]; + + [self _cancelResults]; //No done by WO + + NSDebugMLLog(@"gsdb", @"autoBeginTransaction"); + [adaptorContext autoBeginTransaction: YES]; +/*: + row allKeys + allkey sortedArrayUsingSelector:compare: +each key +*/ + + enumerator = [row keyEnumerator]; + while ((attrName = [enumerator nextObject])) + { + EOAttribute *attribute = nil; + NSString *externalType = nil; + id value = nil; + + NSDebugMLLog(@"gsdb", @"attrName=%@", attrName); + + attribute=[entity attributeNamed: attrName]; + NSDebugMLLog(@"gsdb", @"attribute=%@", attribute); + + if (!attribute) + return; //??????????? + + value = [row objectForKey: attrName]; + NSDebugMLLog(@"gsdb", @"value=%@", value); + + externalType = [attribute externalType]; + NSDebugMLLog(@"gsdb", @"externalType=%@", externalType); + + /* Insert the binary value into the binaryDataRow dictionary */ + if ([externalType isEqual: @"inversion"]) + { + id binValue = [nrow objectForKey: attrName]; + Oid binOid = [self _insertBinaryData: binValue + forAttribute: attribute]; + value = [NSNumber numberWithLong: binOid]; + } + else if ([externalType isEqual: @"NSString"]) //?? + { + //TODO: database encoding + // [[adaptorContext adaptor] databaseEncoding] + } + + [nrow setObject: value + forKey: attrName]; + } + + NSDebugMLLog(@"gsdb", @"nrow=%@", nrow); + + if ([nrow count] > 0) + { + sqlexpr = [[[_adaptorContext adaptor] expressionClass] + insertStatementForRow: nrow + entity: entity]; + NSDebugMLLog(@"gsdb", @"sqlexpr=%@", sqlexpr); + + if ([self _evaluateExpression: sqlexpr withAttributes: nil] == NO) //call evaluateExpression: + [NSException raise: EOGeneralAdaptorException + format: @"%@ -- %@ 0x%x: cannot insert row for entity '%@'", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + [entity name]]; + } + + [_adaptorContext autoCommitTransaction]; + + EOFLOGObjectFnStop(); +} + +- (unsigned)deleteRowsDescribedByQualifier: (EOQualifier *)qualifier + entity: (EOEntity *)entity +{ + EOSQLExpression *sqlexpr = nil; + unsigned long rows = 0; + Postgres95Context *adaptorContext; + + EOFLOGObjectFnStart(); + + if (![self isOpen]) + [NSException raise: NSInternalInconsistencyException + format: @"%@ -- %@ 0x%x: attempt to delete rows with no open channel", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + + if (!qualifier || !entity) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: qualifier and entity arguments " + @" must not be nil objects", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + + if ([self isFetchInProgress]) + [NSException raise: NSInternalInconsistencyException + format: @"%@ -- %@ 0x%x: attempt to delete rows with fetch in progress", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + + adaptorContext = (Postgres95Context *)[self adaptorContext]; + + [self _cancelResults]; + [_adaptorContext autoBeginTransaction: NO]; + + sqlexpr = [[[_adaptorContext adaptor] expressionClass] + deleteStatementWithQualifier: qualifier + entity: entity]; + + if ([self _evaluateExpression: sqlexpr withAttributes: nil]) + rows = strtoul(PQcmdTuples(_pgResult), NULL, 10); + + [adaptorContext autoCommitTransaction]; + + EOFLOGObjectFnStop(); + return rows; +} + +- (void)selectAttributes: (NSArray *)attributes + fetchSpecification: (EOFetchSpecification *)fetchSpecification + lock: (BOOL)flag + entity: (EOEntity *)entity +{ + EOSQLExpression *sqlExpr = nil; + +//objectForKey:EOAdaptorQuotesExternalNames ret: nil +//lastObject ret NSRegistrationDomain +//objectForKey:NSRegistrationDomain ret dict +//objectForKey:EOAdaptorQuotesExternalNames +//attr count +//PostgreSQLExpression initWithEntity: + //setUseliases:YES +//prepareSelectExpressionWithAttributes:lock:fetchSpecification: +//statement +//adaptorContext +//a con autoBeginTransaction +//end + + EOFLOGObjectFnStart(); + + NSDebugMLog(@"TEST attributesToFetch=%@", [entity attributesToFetch]); + NSDebugMLLog(@"gsdb",@"%@ -- %@ 0x%x: isFetchInProgress=%s", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + ([self isFetchInProgress] ? "YES" : "NO")); + + if (![self isOpen]) + [NSException raise: NSInternalInconsistencyException + format: @"%@ -- %@ 0x%x: attempt to select attributes with no open channel", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + + if ([self isFetchInProgress]) + [NSException raise: NSInternalInconsistencyException + format: @"%@ -- %@ 0x%x: attempt to select attributes with fetch in progress", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + + if (_delegateRespondsTo.shouldSelectAttributes) + if (![_delegate adaptorChannel: self + shouldSelectAttributes: attributes + fetchSpecification: fetchSpecification + lock: flag + entity: entity]) + return; + + NSDebugMLLog(@"gsdb", @"%@ -- %@ 0x%x: isFetchInProgress=%s", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + ([self isFetchInProgress] ? "YES" : "NO")); + + [self _cancelResults]; + + NSDebugMLLog(@"gsdb", @"%@ -- %@ 0x%x: isFetchInProgress=%s", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + ([self isFetchInProgress] ? "YES" : "NO")); + + [_adaptorContext autoBeginTransaction: NO]; + + ASSIGN(_attributes, attributes); +// NSDebugMLLog(@"gsdb",@"00 attributes=%@",_attributes); + + + NSAssert([attributes count] > 0, @"No Attributes"); + + sqlExpr = [[[_adaptorContext adaptor] expressionClass] + selectStatementForAttributes: attributes + lock: flag + fetchSpecification: fetchSpecification + entity: entity]; + + NSDebugMLLog(@"gsdb", @"sqlExpr=%@", sqlExpr); +// NSDebugMLLog(@"gsdb",@"AA attributes=%@",_attributes); + + [self _evaluateExpression: sqlExpr + withAttributes: attributes]; + + NSDebugMLLog(@"gsdb", @"After _evaluate"); +// NSDebugMLLog(@"gsdb",@"BB attributes=%@",_attributes); + [_adaptorContext autoCommitTransaction]; + NSDebugMLLog(@"gsdb", @"After autoCommitTransaction"); + + if (_delegateRespondsTo.didSelectAttributes) + [_delegate adaptorChannel: self + didSelectAttributes: attributes + fetchSpecification: fetchSpecification + lock: flag + entity: entity]; +// NSDebugMLLog(@"gsdb",@"CC attributes=%@",_attributes); + + EOFLOGObjectFnStop(); +} + +- (unsigned int)updateValues: (NSDictionary *)values + inRowsDescribedByQualifier: (EOQualifier *)qualifier + entity: (EOEntity *)entity +{ +//autoBeginTransaction +//entity attributes +//externaltype on each attr +//adaptor expressionClass +//exprclass alloc initwithentity +//expr setUseAliases:NO +//exp prepareUpdateExpressionWithRow:qualifier: +//self evaluateExpression: +//autoCommitTransaction +//return number of affeted rows +//end + + EOSQLExpression *sqlExpr = nil; + NSMutableDictionary *mrow = nil; + NSMutableArray *invAttributes = nil; + NSEnumerator *enumerator = nil; + NSString *attrName = nil; + NSString *externalType = nil; + EOAttribute *attr = nil; + Postgres95Context *adaptorContext = nil; + unsigned long rows = 0; + + EOFLOGObjectFnStart(); + + if (![self isOpen]) + [NSException raise: NSInternalInconsistencyException + format: @"%@ -- %@ 0x%x: attempt to update values with no open channel", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + + if ([self isFetchInProgress]) + [NSException raise: NSInternalInconsistencyException + format: @"%@ -- %@ 0x%x: attempt to update values with fetch in progress", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + + if ([values count] > 0) + { + mrow = [[values mutableCopyWithZone: [values zone]] autorelease]; + + // Get EOAttributes involved in update operation + // Modify "inversion" attributes to NSNumber type with the Oid + + invAttributes = [[[NSMutableArray alloc] initWithCapacity: [mrow count]] + autorelease]; + + enumerator = [values keyEnumerator]; + while ((attrName = [enumerator nextObject])) + { + attr = [entity attributeNamed: attrName]; + externalType = [attr externalType]; + + if (attr == nil) + return 0; //??? +/* + [mrow setObject:[attr adaptorValueByConvertingAttributeValue://Not in WO + [values objectForKey:attrName]] + forKey:attrName]; +*/ + [mrow setObject:[values objectForKey: attrName] + forKey: attrName]; + + if ([externalType isEqual: @"inversion"]) + [invAttributes addObject: attr]; + } + + [self _cancelResults]; //Not in WO + adaptorContext = (Postgres95Context *)[self adaptorContext]; + [adaptorContext autoBeginTransaction: YES]; + + if ([invAttributes count]) + { + // Select with update qualifier to see there is only one row + // to be updated and to get the large objects (to be updatetd) + // Oid from dataserver - there is a hack here based on the fact that + // in update there in only one table and no flattened attributes + + NSDictionary *dbRow = nil; + + sqlExpr = [[[_adaptorContext adaptor] expressionClass] + selectStatementForAttributes: invAttributes + lock: NO + fetchSpecification: + [EOFetchSpecification + fetchSpecificationWithEntityName: [entity name] + qualifier: qualifier + sortOrderings: nil] + entity: entity]; + [self _evaluateExpression: sqlExpr withAttributes: nil]; + + _fetchBlobsOid = YES; + dbRow = [self fetchRowWithZone: NULL]; + _fetchBlobsOid = NO; + + [self _cancelResults]; + + // Update the large objects and modify the row to update with Oid's + + enumerator = [invAttributes objectEnumerator]; + while ((attr = [enumerator nextObject])) + { + Oid oldOid; + Oid newOid; + NSData *data; + + attrName = [attr name]; + data = [mrow objectForKey: attrName]; + + oldOid = [[dbRow objectForKey:attrName] longValue]; + newOid = [self _updateBinaryDataRow: oldOid data: data]; + + [mrow setObject: [NSNumber numberWithUnsignedLong: newOid] + forKey: attrName]; + } + } + + // Now we have all: one and only row to update and binary rows + // (large objects) where updated and their new Oid set in the row + + rows = 0; + + NSDebugMLLog(@"gsdb", @"[mrow count]=%d", [mrow count]); + + if ([mrow count] > 0) + { + sqlExpr = [[[_adaptorContext adaptor] expressionClass] + updateStatementForRow: mrow + qualifier: qualifier + entity: entity]; + + //wo call evaluateExpression: + if ([self _evaluateExpression: sqlExpr withAttributes: nil]) + rows = strtoul(PQcmdTuples(_pgResult), NULL, 10); + } + + [adaptorContext autoCommitTransaction]; + } + + EOFLOGObjectFnStop(); + + return rows; +} + +/* The binaryDataRow should contain only one binary attribute */ + +- (char *)_readBinaryDataRow: (Oid)oid + length: (int *)length + zone: (NSZone *)zone; +{ + int fd; + int len, wrt; + char *bytes; + + if (oid == 0) + { + *length = 0; + return NULL; + } + + fd = lo_open(_pgConn, oid, INV_READ|INV_WRITE); + if (fd < 0) + [NSException raise: Postgres95Exception + format: @"cannot open large object Oid = %ld", oid]; + + lo_lseek(_pgConn, fd, 0, SEEK_END); + len = lo_tell(_pgConn, fd); + lo_lseek(_pgConn, fd, 0, SEEK_SET); + + if (len < 0) + [NSException raise: Postgres95Exception + format: @"error while getting size of large object Oid = %ld", oid]; + + bytes = NSZoneMalloc(zone, len); + wrt = lo_read(_pgConn, fd, bytes, len); + + if (len != wrt) + { + NSZoneFree(zone, bytes); + [NSException raise: Postgres95Exception + format: @"error while reading large object Oid = %ld", oid]; + } + lo_close(_pgConn, fd); + + *length = len; + + return bytes; +} + +- (Oid)_insertBinaryData: (NSData *)binaryData + forAttribute: (EOAttribute *)attr +{ + int len; + const char* bytes; + Oid oid; + int fd, wrt; + + if ((id)binaryData == [EONull null] || binaryData == nil) + return 0; + + len = [binaryData length]; + bytes = [binaryData bytes]; + + oid = lo_creat(_pgConn, INV_READ|INV_WRITE); + if (oid == 0) + [NSException raise: Postgres95Exception + format: @"cannot create large object"]; + + fd = lo_open(_pgConn, oid, INV_READ|INV_WRITE); + if (fd < 0) + [NSException raise: Postgres95Exception + format: @"cannot open large object Oid = %ld", oid]; + + wrt = lo_write(_pgConn, fd, (char *)bytes, len); + + if (len != wrt) + [NSException raise: Postgres95Exception + format: @"error while writing large object Oid = %ld", oid]; + + lo_close(_pgConn, fd); + + return oid; +} + +- (Oid)_updateBinaryDataRow: (Oid)oid + data: (NSData *)binaryData +{ + int len; + const char* bytes; + int wrt, fd; + + if (oid) + lo_unlink(_pgConn, oid); + + if ((id)binaryData == [EONull null] || binaryData == nil) + return 0; + + len = [binaryData length]; + bytes = [binaryData bytes]; + + oid = lo_creat(_pgConn, INV_READ|INV_WRITE); + if (oid == 0) + [NSException raise: Postgres95Exception + format: @"cannot create large object"]; + + fd = lo_open(_pgConn, oid, INV_READ|INV_WRITE); + if (fd < 0) + [NSException raise: Postgres95Exception + format: @"cannot open large object Oid = %ld", oid]; + + wrt = lo_write(_pgConn, fd, (char*)bytes, len); + + if (len != wrt) + [NSException raise: Postgres95Exception + format: @"error while writing large object Oid = %ld", oid]; + + lo_close(_pgConn, fd); + + return oid; +} + +/* Read type oid and names from the database server. + Called on each openChannel to refresh info. */ +- (void)_describeDatabaseTypes +{ + int i, count; + + _pgResult = PQexec(_pgConn, + "SELECT oid, typname FROM pg_type WHERE typrelid = 0"); + + if (_pgResult == NULL || PQresultStatus(_pgResult) != PGRES_TUPLES_OK) + { + _pgResult = NULL; + [NSException raise: Postgres95Exception + format: @"cannot read type name informations from database. " + @"bad response from server"]; + } + + if (PQnfields(_pgResult) != 2) + { + _pgResult = NULL; + [NSException raise: Postgres95Exception + format: @"cannot read type name informations from database. " + @"results should have two columns"]; + } + + [_oidToTypeName removeAllObjects]; + count = PQntuples(_pgResult); + + for (i = 0; i < count; i++) + { + char* oid = PQgetvalue(_pgResult, i, 0); + char* typ = PQgetvalue(_pgResult, i, 1); + + [_oidToTypeName setObject: [NSString stringWithCString: typ] + forKey: [NSNumber numberWithLong: atol(oid)]]; + } + + PQclear(_pgResult); + _pgResult = NULL; +} + +- (NSArray *)attributesToFetch +{ + return _attributes; +} + +- (void)setAttributesToFetch: (NSArray *)attributes +{ + //call adaptorContext + NSDebugMLLog(@"gsdb", @"Postgres95Channel: setAttributesToFetch %p:%@", + attributes, attributes); + + ASSIGN(_attributes, attributes); +} + +- (NSArray *)describeResults +{ + NSArray *desc; + + EOFLOGObjectFnStart(); + + if (![self isFetchInProgress]) + [NSException raise: NSInternalInconsistencyException + format: @"%@ -- %@ 0x%x: attempt to describe results with no fetch in progress", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + + desc = [self attributesToFetch]; + + EOFLOGObjectFnStop(); + + return desc; +} + +- (void)_describeResults +{ + int colsNumber; + + EOFLOGObjectFnStart(); + + colsNumber=_pgResult ? PQnfields(_pgResult): 0; + NSDebugMLLog(@"gsdb", @"colsNumber=%d", colsNumber); + + if (colsNumber == 0) + { + [self setAttributesToFetch: [NSArray array]]; + } + else if (!_attributes) //?? + { + int i; + id *attributes = NULL; + + attributes = alloca(colsNumber * sizeof(id)); + + for (i = 0; i < colsNumber; i++) + { + EOAttribute *attribute = [[EOAttribute new] autorelease]; + NSString *externalName; + NSString *valueClass = @"NSString"; + NSString *valueType = nil; + NSDebugMLog(@"TEST attributesToFetch=%@", + [[attribute entity] attributesToFetch]); + + if (_origAttributes) + { + EOAttribute *origAttr = (EOAttribute *)[_origAttributes + objectAtIndex: i]; + + [attribute setName: [origAttr name]]; + [attribute setColumnName: [origAttr columnName]]; + [attribute setExternalType: [origAttr externalType]]; + [attribute setValueType: [origAttr valueType]]; + [attribute setValueClassName: [origAttr valueClassName]]; + } + else + { + externalName = [_oidToTypeName + objectForKey: [NSNumber + numberWithLong: PQftype(_pgResult, i)]]; + + if (!externalName) + [NSException raise: Postgres95Exception + format: @"cannot find type for Oid = %d", + PQftype(_pgResult, i)]; + + [attribute setName: [NSString stringWithFormat: @"attribute%d", i]]; + [attribute setColumnName: @"unknown"]; + [attribute setExternalType: externalName]; + + if ([externalName isEqual: @"bool"]) + valueClass = @"NSNumber", valueType = @"c"; + else if ([externalName isEqual: @"char"]) + valueClass = @"NSNumber", valueType = @"c"; + else if ([externalName isEqual: @"dt"]) + valueClass = @"NSCalendarDate", valueType = nil; + else if ([externalName isEqual: @"date"]) + valueClass = @"NSCalendarDate", valueType = nil; + else if ([externalName isEqual: @"time"]) + valueClass = @"NSCalendarDate", valueType = nil; + else if ([externalName isEqual: @"float4"]) + valueClass = @"NSNumber", valueType = @"f"; + else if ([externalName isEqual: @"float8"]) + valueClass = @"NSNumber", valueType = @"d"; + else if ([externalName isEqual: @"int2"]) + valueClass = @"NSNumber", valueType = @"i"; + else if ([externalName isEqual: @"int4"]) + valueClass = @"NSNumber", valueType = @"i"; + else if ([externalName isEqual: @"int8"]) + valueClass = @"NSNumber", valueType = @"l"; + else if ([externalName isEqual: @"oid"]) + valueClass = @"NSNumber", valueType = @"l"; + else if ([externalName isEqual: @"varchar"]) + valueClass = @"NSString", valueType = nil; + else if ([externalName isEqual: @"bpchar"]) + valueClass = @"NSString", valueType = nil; + else if ([externalName isEqual: @"text"]) + valueClass = @"NSString", valueType = nil; + /* else if ([externalName isEqual:@"cid"]) + valueClass = @"NSNumber", valueType = @""; + else if ([externalName isEqual:@"tid"]) + valueClass = @"NSNumber", valueType = @""; + else if ([externalName isEqual:@"xid"]) + valueClass = @"NSNumber", valueType = @"";*/ + + [attribute setValueType: valueType]; + [attribute setValueClassName: valueClass]; + } + + attributes[i] = attribute; + NSDebugMLog(@"TEST attributesToFetch=%@", + [[attribute entity] attributesToFetch]); + } + + [self setAttributesToFetch: [[[NSArray alloc] + initWithObjects: attributes + count: colsNumber] autorelease]]; + } +// NSDebugMLLog(@"gsdb",@"_attributes=%@",_attributes); + + EOFLOGObjectFnStop(); +} + +/* The methods used to generate an model from the meta-information kept by + the database. */ + +- (NSArray *)describeTableNames +{ + // TODO + [self notImplemented: _cmd]; + return nil; +} + +- (NSArray *)describeStoredProcedureNames +{ + // TODO + [self notImplemented: _cmd]; + return nil; +} + +- (EOModel *)describeModelWithTableNames: (NSArray *)tableNames +{ + NSEnumerator *tableEnum; + NSString *table; + EOModel *model; + EOEntity *entity; + + model = [[[EOModel alloc] init] autorelease]; + + tableEnum = [tableNames objectEnumerator]; + + while ((table = [tableEnum nextObject])) + { + entity = [[[EOEntity alloc] init] autorelease]; + [entity setExternalName: table]; + [model addEntity: entity]; + } + + return model; //TODO +} + +- (void)setDelegate:delegate +{ + [super setDelegate: delegate]; + + _postgres95DelegateRespondsTo.postgres95InsertedRowOid = + [delegate respondsToSelector: + @selector(postgres95Channel:insertedRowWithOid:)]; + _postgres95DelegateRespondsTo.postgres95Notification = + [delegate respondsToSelector: + @selector(postgres95Channel:receivedNotification:)]; +} + +- (NSDictionary *)primaryKeyForNewRowWithEntity:(EOEntity *)entity +{ +//entity primaryKeyAttributes +//self adaptorContext +//on each attr attr: adaptorValueType +//entty externalName +//context autoBeginTransaction +//self cleanupFetch###### +//attr name +//dictionary with... + NSDictionary *pk = nil; + NSString *sqlString; + NSString *key = nil; + NSNumber *pkValue = nil; + const char *string = NULL; + int length = 0; + NSString *primaryKeySequenceNameFormat; + NSString *sequenceName; + + EOFLOGObjectFnStart(); + + primaryKeySequenceNameFormat = [(Postgres95Context*)[self adaptorContext] + primaryKeySequenceNameFormat]; + NSAssert(primaryKeySequenceNameFormat, @"No primary sequence name format"); + + sequenceName = [NSString stringWithFormat: primaryKeySequenceNameFormat, + [entity externalName]]; + sqlString = [NSString stringWithFormat: @"SELECT nextval('%@')", + sequenceName]; + + [self _cancelResults]; + [_adaptorContext autoBeginTransaction: NO]; + + [self _evaluateExpression: [EOSQLExpression expressionForString:sqlString] + withAttributes: _pkAttributeArray]; + + if ([self isFetchInProgress] == NO + || [self advanceRow] == NO) + { + [self _cancelResults]; + [_adaptorContext autoCommitTransaction]; + } + else + { + string = PQgetvalue(_pgResult, _currentResultRow, 0); + length = PQgetlength(_pgResult, _currentResultRow, 0); + + pkValue = [[Postgres95Values newValueForBytes: string + length: length + attribute: [_pkAttributeArray + objectAtIndex: 0]] + autorelease]; + + NSAssert(pkValue, @"no pk value"); + key = [[entity primaryKeyAttributeNames] objectAtIndex: 0]; + NSAssert(key, @"pk key"); + + [self _cancelResults]; + [_adaptorContext autoCommitTransaction]; + + pk = [NSDictionary dictionaryWithObject: pkValue + forKey: key]; + } + + EOFLOGObjectFnStop(); + + return pk; +} + +- (void)cleanupFetch +{ + Postgres95Context *adaptorContext; + + EOFLOGObjectFnStart(); + + adaptorContext = (Postgres95Context *)[self adaptorContext]; + + NSDebugMLog(@"[self isFetchInProgress]=%s", + ([self isFetchInProgress] ? "YES" : "NO")); + + if ([self isFetchInProgress]) + { + BOOL ok; + + [self _cancelResults]; + + ok = [adaptorContext autoCommitTransaction]; + //_isTransactionstarted to 0 + //_evaluationIsDirectCalled=0 + } + + EOFLOGObjectFnStop(); +} + +@end /* Postgres95Channel */ diff --git a/EOAdaptors/Postgres95/Postgres95Context.h b/EOAdaptors/Postgres95/Postgres95Context.h new file mode 100644 index 0000000..e84e929 --- /dev/null +++ b/EOAdaptors/Postgres95/Postgres95Context.h @@ -0,0 +1,71 @@ +/* + Postgres95Context.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + based on the Postgres95 adaptor written by + Mircea Oancea + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __Postgres95Context_h__ +#define __Postgres95Context_h__ + +#import +#import + + +@interface Postgres95Context : EOAdaptorContext +{ + NSString* _primaryKeySequenceNameFormat; + struct + { + unsigned int didAutoBegin:1; + unsigned int didBegin:1; + unsigned int forceTransaction:1; + } _flags; +} + +- initWithAdaptor: (EOAdaptor *)adaptor; + +- (void)beginTransaction; +- (void)commitTransaction; +- (void)rollbackTransaction; + +- (BOOL)canNestTransactions; + +- (EOAdaptorChannel *)createAdaptorChannel; + +- (BOOL)autoBeginTransaction: (BOOL)force; +- (BOOL)autoCommitTransaction; + +// format is something like @"%@_SEQ" or @"EOSEQ_%@", "%@" is replaced by external table name +- (void)setPrimaryKeySequenceNameFormat: (NSString*)format; +- (NSString*)primaryKeySequenceNameFormat; + +- (BOOL)autoBeginTransaction: (BOOL)force; +- (BOOL)autoCommitTransaction; + +@end + + +#endif /* __Postgres95Context_h__ */ diff --git a/EOAdaptors/Postgres95/Postgres95Context.m b/EOAdaptors/Postgres95/Postgres95Context.m new file mode 100644 index 0000000..9072389 --- /dev/null +++ b/EOAdaptors/Postgres95/Postgres95Context.m @@ -0,0 +1,318 @@ +/** + Postgres95Context.m Postgres95Context + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + based on the Postgres95 adaptor written by + Mircea Oancea + + Author: Manuel Guesdon + Date: October 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import +#import +#import + +#import + +#import +#import +#import +#import + + +@implementation Postgres95Context + +- (id)initWithAdaptor: (EOAdaptor *)adaptor +{ + if ((self = [super initWithAdaptor: adaptor])) + { + if (adaptor) + [self setPrimaryKeySequenceNameFormat: + [(Postgres95Adaptor*)adaptor primaryKeySequenceNameFormat]]; + } + + return self; +} + +- (void)beginTransaction +{ + Postgres95Channel *channel = nil; + + EOFLOGObjectFnStart(); + + if ([self transactionNestingLevel]) + [NSException raise: NSInternalInconsistencyException + format: @"%@ -- %@ 0x%x: attempted to begin a transaction within a transaction", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + + if (_delegateRespondsTo.shouldBegin) + { + if (![_delegate adaptorContextShouldBegin: self]) + [NSException raise: Postgres95Exception + format: @"%@ -- %@ 0x%x: delegate refuses", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + } + + channel = [[_channels objectAtIndex: 0] nonretainedObjectValue]; + + if ([channel isOpen] == NO) + [NSException raise: Postgres95Exception + format: @"cannot execute SQL expression. Channel is not opened."]; + + _flags.didBegin = YES; + + [channel _evaluateExpression: [EOSQLExpression + expressionForString: @"BEGIN TRANSACTION"] + withAttributes: nil]; + + [self transactionDidBegin]; + + if (_delegateRespondsTo.didBegin) + [_delegate adaptorContextDidBegin: self]; + + NSDebugMLLog(@"gsdb", @"_flags.didBegin=%s", + (_flags.didBegin ? "YES" : "NO")); + NSDebugMLLog(@"gsdb", @"_flags.didAutoBegin=%s", + (_flags.didAutoBegin ? "YES" : "NO")); + + EOFLOGObjectFnStop(); +} + +- (void)commitTransaction +{ +//channel conn +//self transactionNestingLevel +//self transactionDidCommit + EOFLOGObjectFnStart(); + + NSDebugMLLog(@"gsdb", @"_flags.didBegin=%s", + (_flags.didBegin ? "YES" : "NO")); + NSDebugMLLog(@"gsdb", @"_flags.didAutoBegin=%s", + (_flags.didAutoBegin ? "YES" : "NO")); + + if ([self transactionNestingLevel] == 0) + [NSException raise: NSInternalInconsistencyException + format: @"%@ -- %@ 0x%x:illegal attempt to commit a transaction when there are none in progress", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + + if (_delegateRespondsTo.shouldCommit) + { + if (![_delegate adaptorContextShouldCommit: self]) + [NSException raise: Postgres95Exception + format: @"%@ -- %@ 0x%x: delegate refuses", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + } +//??? + [[[_channels objectAtIndex: 0] nonretainedObjectValue] + _evaluateExpression: [EOSQLExpression + expressionForString: @"END TRANSACTION"] + withAttributes: nil]; + + _flags.didBegin = NO; + + [self transactionDidCommit]; + + if (_delegateRespondsTo.didCommit) + [_delegate adaptorContextDidCommit: self]; + + NSDebugMLLog(@"gsdb", @"_flags.didBegin=%s", + (_flags.didBegin ? "YES" : "NO")); + NSDebugMLLog(@"gsdb", @"_flags.didAutoBegin=%s", + (_flags.didAutoBegin ? "YES" : "NO")); + + EOFLOGObjectFnStop(); +} + +- (void)rollbackTransaction +{ + EOFLOGObjectFnStart(); + + NSDebugMLLog(@"gsdb", @"_flags.didBegin=%s", + (_flags.didBegin ? "YES" : "NO")); + NSDebugMLLog(@"gsdb", @"_flags.didAutoBegin=%s", + (_flags.didAutoBegin ? "YES" : "NO")); + + if (![self transactionNestingLevel]) + { + [NSException raise: NSInternalInconsistencyException + format: @"%@ -- %@ 0x%x:illegal attempt to commit a transaction when there are none in progress", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + } + + if (_delegateRespondsTo.shouldRollback) + { + if (![_delegate adaptorContextShouldRollback: self]) + [NSException raise: Postgres95Exception + format: @"%@ -- %@ 0x%x: delegate refuses", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + } + + [[[_channels objectAtIndex: 0] nonretainedObjectValue] + _evaluateExpression: [EOSQLExpression + expressionForString: @"ABORT TRANSACTION"] + withAttributes: nil]; + + _flags.didBegin = NO; + + [self transactionDidRollback]; + + if (_delegateRespondsTo.didRollback) + [_delegate adaptorContextDidRollback: self]; + + NSDebugMLLog(@"gsdb", @"_flags.didBegin=%s", + (_flags.didBegin ? "YES" : "NO")); + NSDebugMLLog(@"gsdb", @"_flags.didAutoBegin=%s", + (_flags.didAutoBegin ? "YES" : "NO")); + + EOFLOGObjectFnStop(); +} + +- (BOOL)canNestTransactions +{ + return NO; +} + +- (EOAdaptorChannel *)createAdaptorChannel +{ + //OK + EOAdaptorChannel *adaptorChannel; + + adaptorChannel = [Postgres95Channel adaptorChannelWithAdaptorContext: self]; + + return adaptorChannel; +} + +- (BOOL)autoBeginTransaction: (BOOL)force +{ + //seems OK + BOOL ok = NO; + + EOFLOGObjectFnStart(); + + NSDebugMLLog(@"gsdb", @"force=%d _flags.didBegin=%s [self transactionNestingLevel]=%d", + force, + (_flags.didBegin ? "YES" : "NO"), + [self transactionNestingLevel]); + + if (!_flags.didBegin && [self transactionNestingLevel] == 0) + { + if (force == YES) + [self beginTransaction]; + + _flags.didAutoBegin = YES; + _flags.forceTransaction = force; + + ok = YES; + } + + NSDebugMLLog(@"gsdb", @"_flags.didBegin=%s", + (_flags.didBegin ? "YES" : "NO")); + NSDebugMLLog(@"gsdb", @"_flags.didAutoBegin=%s", + (_flags.didAutoBegin ? "YES" : "NO")); + + EOFLOGObjectFnStop(); + + return ok; +} + +- (BOOL)autoCommitTransaction +{ +//seems ok + BOOL ok = NO; + + EOFLOGObjectFnStart(); + + NSDebugMLLog(@"gsdb", @"_flags.didBegin=%s", + (_flags.didBegin ? "YES" : "NO")); + NSDebugMLLog(@"gsdb", @"_flags.didAutoBegin=%s", + (_flags.didAutoBegin ? "YES" : "NO")); + + if (_flags.didAutoBegin) + { + NSDebugMLLog(@"gsdb", @"_flags.forceTransaction=%s", + (_flags.forceTransaction ? "YES" : "NO")); + + if (_flags.forceTransaction == YES) + { + [self commitTransaction]; + } + + _flags.didAutoBegin = NO; + _flags.forceTransaction = NO; + + ok = YES; + } + + NSDebugMLLog(@"gsdb", @"_flags.didBegin=%s", + (_flags.didBegin ? "YES" : "NO")); + NSDebugMLLog(@"gsdb", @"_flags.didAutoBegin=%s", + (_flags.didAutoBegin ? "YES" : "NO")); + + EOFLOGObjectFnStop(); + + return ok; +} + +/** format is something like @"%@_SEQ" or @"EOSEQ_%@", "%@" is replaced by external table name **/ +- (void)setPrimaryKeySequenceNameFormat: (NSString*)format +{ + ASSIGN(_primaryKeySequenceNameFormat, format); +} + +- (NSString*)primaryKeySequenceNameFormat +{ + return _primaryKeySequenceNameFormat; +} + +@end /* Postgres95Context */ +/* +//TODO +autoCommitTransaction +{ +self commitTransaction +}; +*/ diff --git a/EOAdaptors/Postgres95/Postgres95EOAdaptor.gsdoc b/EOAdaptors/Postgres95/Postgres95EOAdaptor.gsdoc new file mode 100644 index 0000000..0b3004b --- /dev/null +++ b/EOAdaptors/Postgres95/Postgres95EOAdaptor.gsdoc @@ -0,0 +1,23 @@ + + + + + GDL2 Postgres95 Adaptor + + + + + + + + + + GDL2 Postgres95 Adaptor +

... +

+
+ + + + +
diff --git a/EOAdaptors/Postgres95/Postgres95SQLExpression.h b/EOAdaptors/Postgres95/Postgres95SQLExpression.h new file mode 100644 index 0000000..551be9e --- /dev/null +++ b/EOAdaptors/Postgres95/Postgres95SQLExpression.h @@ -0,0 +1,57 @@ +/* + Postgres95SQLExpression.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __Postgres95SQLExpression_h__ +#define __Postgres95SQLExpression_h__ + +#import + + +@class NSString; + + +@interface Postgres95SQLExpression : EOSQLExpression + ++ (NSString *)formatValue: (id)value + forAttribute: (EOAttribute *)attribute; +- (NSString *)externalNameQuoteCharacter; +- (NSString *)lockClause; +- (NSString *)assembleSelectStatementWithAttributes: (NSArray *)attributes + lock: (BOOL)lock + qualifier: (EOQualifier *)qualifier + fetchOrder: (NSArray *)fetchOrder + selectString: (NSString *)selectString + columnList: (NSString *)columnList + tableList: (NSString *)tableList + whereClause: (NSString *)whereClause + joinClause: (NSString *)joinClause + orderByClause: (NSString *)orderByClause + lockClause: (NSString *)lockClause; + +@end + + +#endif /* __Postgres95SQLExpression_h__ */ diff --git a/EOAdaptors/Postgres95/Postgres95SQLExpression.m b/EOAdaptors/Postgres95/Postgres95SQLExpression.m new file mode 100644 index 0000000..33700df --- /dev/null +++ b/EOAdaptors/Postgres95/Postgres95SQLExpression.m @@ -0,0 +1,299 @@ +/** + Postgres95SQLExpression.m Postgres95SQLExpression + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + This product includes software developed by Turbocat's Development. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import + +#import + +#import + +#import +#import + + +@implementation Postgres95SQLExpression + ++ (NSString *)formatValue: (id)value + forAttribute: (EOAttribute *)attribute +{ + NSString *formatted = nil; + NSString *externalType; + NSMutableString *string; + const char *tempString; + int i, dif; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"value=%@ class=%@", value, + [value class]); + EOFLOGObjectLevelArgs(@"EOSQLExpression", + @"[EONull null] %p=%@ [EONull null] class=%@", + [EONull null], + [EONull null], + [[EONull null] class]); + EOFLOGObjectLevelArgs(@"EOSQLExpression", + @"[value isEqual:[EONull null]]=%s", + ([value isEqual: [EONull null]] ? "YES" : "NO")); + + externalType = [attribute externalType]; + + if (!value) + { + EOFLOGObjectLevelArgs(@"EOSQLExpression", + @"NULL case - value=%@ class=%@", + value, [value class]); + + formatted = @"NULL"; + } + else if ([value isEqual: [EONull null]]) + { + EOFLOGObjectLevelArgs(@"EOSQLExpression", + @"EONULL case - value=%@ class=%@", + value, [value class]); + + formatted = [value sqlString]; + } + else if ([externalType hasPrefix: @"int"]) + { + EOFLOGObjectLevelArgs(@"EOSQLExpression", + @"int case - value=%@ class=%@", + value, [value class]); + + formatted = [NSString stringWithFormat: @"%@", value]; + + // value was for example 0 length string + if ([formatted length] == 0) + formatted = @"NULL"; + } + else if ([externalType hasPrefix: @"float"]) + { + EOFLOGObjectLevelArgs(@"EOSQLExpression", + @"float case - value=%@ class=%@", + value, [value class]); + + formatted = [NSString stringWithFormat: @"%@", value]; + + // value was for example 0 length string + if ([formatted length] == 0) + formatted=@"NULL"; + } + else if ([externalType hasPrefix: @"bool"]) + { + EOFLOGObjectLevelArgs(@"EOSQLExpression", + @"BOOL case - value=%@ class=%@", + value, [value class]); + + if ([value isKindOfClass: [NSNumber class]] == YES) + { + BOOL boolValue = [value boolValue]; + + if (boolValue == NO) + formatted = @"'f'"; + else + formatted = @"'t'"; + } + else + { + EOFLOGObjectLevelArgs(@"EOSQLExpression", + @"BOOL case/NSString - value=%@ class=%@", + value, [value class]); + + formatted = [NSString stringWithFormat: @"'%@'", value]; + + // value was for example 0 length string + if ([formatted length] == 0) + formatted = @"NULL"; + } + } + else if ([externalType isEqualToString: @"oid"]) + { + EOFLOGObjectLevelArgs(@"EOSQLExpression", + @"OID case - value=%@ class=%@", + value, [value class]); + + formatted = [NSString stringWithFormat: @"%@", value]; + + // value was for example 0 length string + if ([formatted length] == 0) + formatted=@"NULL"; + } + else if ([externalType isEqualToString: @"money"]) + { + EOFLOGObjectLevelArgs(@"EOSQLExpression", + @"Money case - value=%@ class=%@", + value, [value class]); + + formatted = [NSString stringWithFormat: @"'$%@'", value]; + + // value was for example 0 length string + if ([formatted length] == 3) // only '$' + formatted = @"NULL"; + } + else if (([externalType isEqualToString: @"abstime"]) + || ([externalType isEqualToString: @"datetime"]) + || ([externalType isEqualToString: @"timestamp"])) + { + EOFLOGObjectLevelArgs(@"EOSQLExpression", + @"Time case - value=%@ class=%@", + value, [value class]); + + if ([[value description] length] == 0) + { + NSWarnLog(@"empty description for %p %@ of class %@", + value, value, [value class]); + } + // Value can also be a string... + if ([value isKindOfClass:[NSDate class]]) + { + formatted = [NSString stringWithFormat: @"'%@'", + [value + descriptionWithCalendarFormat: + [NSCalendarDate postgres95Format]//@"%d/%m/%Y %H:%M:%S" + timeZone: nil + locale: nil]]; + } + else + formatted = [NSString stringWithFormat: @"'%@'",value]; + } + else + { + int length = 0; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", + @"other case - value=%@ class=%@", + value, [value class]); + + string = [NSMutableString stringWithFormat: @"%@", value]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"string %p='%@'", + string, string); + + length=[string cStringLength]; + tempString = [string cString]; + + for (i = 0, dif = 0; i < length; i++) + { + switch (tempString[i]) + { + case '\\': + case '\'': + [string insertString: @"\\" atIndex: dif + i]; + dif++; + break; + case '_': + [string insertString: @"\\" atIndex: dif + i]; + dif++; + break; + default: + break; + } + } + + formatted = [NSString stringWithFormat: @"'%@'", string]; + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"formatted %p=%@", + formatted, formatted); + } + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"formatted=%@", formatted); + + EOFLOGObjectFnStop(); + + return formatted; +} + +- (NSString *)externalNameQuoteCharacter +{ + if ([EOSQLExpression useQuotedExternalNames]) + return @"'"; + else + return @""; +} + +- (NSString *)lockClause +{ + return @"FOR UPDATE"; +} + +- (NSString *)assembleSelectStatementWithAttributes: (NSArray *)attributes + lock: (BOOL)lock + qualifier: (EOQualifier *)qualifier + fetchOrder: (NSArray *)fetchOrder + selectString: (NSString *)selectString + columnList: (NSString *)columnList + tableList: (NSString *)tableList + whereClause: (NSString *)whereClause + joinClause: (NSString *)joinClause + orderByClause: (NSString *)orderByClause + lockClause: (NSString *)lockClause +{ + //OK + NSMutableString *sqlString = nil; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"selectString=%@", selectString); + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"columnList=%@", columnList); + EOFLOGObjectLevelArgs(@"EOSQLExpression", @"tableList=%@", tableList); + + sqlString = [NSMutableString stringWithFormat: @"%@ %@ FROM %@", + selectString, + columnList, + tableList]; + + if (whereClause && joinClause) + [sqlString appendFormat: @" WHERE %@ AND %@", + whereClause, + joinClause]; + else if (whereClause || joinClause) + [sqlString appendFormat: @" WHERE %@", + (whereClause ? whereClause : joinClause)]; + + if (orderByClause) + [sqlString appendFormat: @" ORDER BY %@", orderByClause]; + + if (lockClause) + [sqlString appendFormat: @" %@", lockClause]; + + EOFLOGObjectFnStop(); + + return sqlString; +} + + +@end + diff --git a/EOAdaptors/Postgres95/Postgres95Values.h b/EOAdaptors/Postgres95/Postgres95Values.h new file mode 100644 index 0000000..9db9f69 --- /dev/null +++ b/EOAdaptors/Postgres95/Postgres95Values.h @@ -0,0 +1,79 @@ +/* + Postgres95Values.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani +#import +#import +#import + +#import + + +@class EOAttribute; +@class Postgres95Channel; + + +extern NSString *Postgres95CalendarFormat; + + +@interface Postgres95Values +{ +} + ++ (id)newValueForBytes: (const void *)bytes + length: (int)length + attribute: (EOAttribute *)attribute; + + ++ (id)newValueForNumberType: (const void *)bytes + length: (int)length + attribute: (EOAttribute *)attribute; + ++ (id)newValueForCharactersType: (const void *)bytes + length: (int)length + attribute: (EOAttribute *)attribute; + ++ (id)newValueForBytesType: (const void *)bytes + length: (int)length + attribute: (EOAttribute *)attribute; + ++ (id)newValueForDateType: (const void *)bytes + length: (int)length + attribute: (EOAttribute *)attribute; + +@end + +@interface NSCalendarDate (Postgres95ValueCreation) + ++ (void)setPostgres95Format: (NSString *)_format; ++ (NSString *)postgres95Format; + +@end + +#endif /* __Postgres95Values_h__ */ diff --git a/EOAdaptors/Postgres95/Postgres95Values.m b/EOAdaptors/Postgres95/Postgres95Values.m new file mode 100644 index 0000000..5655985 --- /dev/null +++ b/EOAdaptors/Postgres95/Postgres95Values.m @@ -0,0 +1,330 @@ +/** + Postgres95Values.m + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import +#import +#import + +#import + +#import +#import + +#import +#import +#import + + +void __postgres95_values_linking_function (void) +{ +} + +//NSString *Postgres95CalendarFormat = @"%m-%d-%Y %H:%M:%S %Z"; +NSString *Postgres95CalendarFormat = nil; + +@implementation Postgres95Values + + ++ (id)newValueForBytes: (const void *)bytes + length: (int)length + attribute: (EOAttribute *)attribute +{ + switch ([attribute adaptorValueType]) + { + case EOAdaptorNumberType: + return [self newValueForNumberType: bytes + length: length + attribute: attribute]; + case EOAdaptorCharactersType: + return [self newValueForCharactersType: bytes + length: length + attribute: attribute]; + case EOAdaptorBytesType: + return [self newValueForBytesType: bytes + length: length + attribute: attribute]; + case EOAdaptorDateType: + return [self newValueForDateType: bytes + length: length + attribute: attribute]; + } + + return nil; +} + +/** +For efficiency reasons, the returned value is NOT autoreleased ! +**/ ++ (id)newValueForNumberType: (const void *)bytes + length: (int)length + attribute: (EOAttribute *)attribute +{ + NSString *str = [NSString stringWithCString:(char *)bytes + length:length]; + id value = nil; + + if ([[attribute externalType] isEqualToString: @"bool"]) + { + if (((char *)bytes)[0] == 't' && ((char *)bytes)[1] == 0) + return [[NSNumber alloc] initWithBool:YES]; + if (((char *)bytes)[0] == 'f' && ((char *)bytes)[1] == 0) + return [[NSNumber alloc] initWithBool:NO]; + } + + if ([[attribute valueClassName] isEqualToString: @"NSDecimalNumber"]) + value = [[NSDecimalNumber decimalNumberWithString: str] retain]; + else if ([[attribute valueType] isEqualToString: @"i"]) + value = [[NSNumber alloc] initWithInt: [str intValue]]; + else + value = [[NSNumber alloc] initWithDouble: [str doubleValue]]; + + return value; +} + +/** +For efficiency reasons, the returned value is NOT autoreleased ! +**/ ++ (id)newValueForCharactersType: (const void *)bytes + length: (int)length + attribute: (EOAttribute *)attribute +{ + return [attribute newValueForBytes: bytes + length: length + encoding: [NSString defaultCStringEncoding]]; +} + +/** +For efficiency reasons, the returned value is NOT autoreleased ! +**/ ++ (id)newValueForBytesType: (const void *)bytes + length: (int)length + attribute: (EOAttribute *)attribute +{ + return [attribute newValueForBytes: bytes + length: length]; +} + + +/** +For efficiency reasons, the returned value is NOT autoreleased ! +**/ ++ (id)newValueForDateType: (const void *)bytes + length: (int)length + attribute: (EOAttribute *)attribute +{ + id d; + NSString *str = [NSString stringWithCString: bytes length: length]; + NSString *format = [NSCalendarDate postgres95Format]; + + d = [[[NSCalendarDate alloc] initWithString: str + calendarFormat: format] + // TODO server TZ ? + retain]; + +// NSDebugMLLog(@"gsdb",@"str=%@ d=%@ format=%@",str,d,format); + NSDebugMLog(@"str=%@ d=%@ format=%@", str, d, format); + + return d; +} + + +@end +/* +@implementation NSString (Postgres95ValueCreation) + + +For efficiency reasons, the returned value is NOT autoreleased ! + +- stringValueForPostgres95Type:(NSString*)type + attribute:(EOAttribute*)attribute +{ +if ([type isEqual:@"bytea"]) + return [[NSData alloc]initWithBytes:[self cString] + length:[self cStringLength]] + stringValueForPostgres95Type:type + attribute:attribute]; + else + return [[[[EOQuotedExpression alloc] + initWithExpression:self + quote:@"'" + escape:@"\\'"] + autorelease] + expressionValueForContext:nil]; + return nil; +} + +@end // NSString (Postgres95ValueCreation) + + + +@implementation NSNumber (Postgres95ValueCreation) + +- stringValueForPostgres95Type:(NSString*)type + attribute:(EOAttribute*)attribute; +{ + if ([[attribute externalType] isEqualToString:@"bool"]) + return [self boolValue] ? @"'t'" : @"'f'"; + + return [self description]; +} + +@end // NSNumber (Postgres95ValueCreation) + + +@implementation NSData (Postgres95ValueCreation) + + +- stringValueForPostgres95Type:(NSString*)type + attribute:(EOAttribute*)attribute +{ + if ([[attribute externalType] isEqualToString:@"bytea"]) { + const char* bytes = [self bytes]; + int length = [self length]; + int final_length; + char *description, *temp; + int i; + + if (!length) + return @"''"; + + final_length = 4 + 2 * length + 1; + description = Malloc (final_length); + temp = description + 3; + + description[0] = 0; + strcat (description, "'0x"); + for (i = 0; i < length; i++, temp += 2) + sprintf (temp, "%02X", (unsigned char)bytes[i]); + temp[0] = '\''; + temp[1] = 0; + + return [[[NSString alloc] + initWithCStringNoCopy:description + length:final_length-1 + freeWhenDone:YES] + autorelease]; + } + + return [[NSString stringWithCString:[self bytes] length:[self length]] + stringValueForPostgres95Type:type attribute:attribute]; +} + +@end // NSData (Postgres95ValueCreation) + +*/ +@implementation NSCalendarDate (Postgres95ValueCreation) +/* +- stringValueForPostgres95Type:(NSString*)type + attribute:(EOAttribute*)attribute +{ + NSString* externalType = [attribute externalType]; + if (!CALENDAR_FORMAT) + [NSCalendarDate setPostgres95Format:[NSString stringWithCString:"%b %d %Y %I:%M%p %Z"]]; + + if ([externalType isEqualToString:@"abstime"]) { + id tz = [attribute serverTimeZone]; + id date; + + if (tz) { + date = [[self copy] autorelease]; + [date setTimeZone:tz]; + } + else + date = self; + + return [NSString stringWithFormat:@"'%@'", + [date descriptionWithCalendarFormat:CALENDAR_FORMAT]]; + } + + THROW([[DataTypeMappingNotSupportedException alloc] + initWithFormat:@"Postgres95 cannot map NSCalendarDate in " + @"attribute %@ to external type %@", + [attribute name], externalType]); + return nil; +} +*/ + ++ (NSString*)postgres95Format +{ + if (!Postgres95CalendarFormat) + //Mirko: @"%d/%m/%Y %H:%M:%S.00 %Z" + [NSCalendarDate setPostgres95Format: [NSString stringWithCString: "%m-%d-%Y %H:%M:%S %Z"]]; //"%b %d %Y %I:%M%p %Z"]]; + + return Postgres95CalendarFormat; +} + ++ (void)setPostgres95Format: (NSString*)_format +{ + ASSIGN(Postgres95CalendarFormat, _format); +} + + +@end // NSCalendarDate (Postgres95ValueCreation) + +/* +@implementation EONull (Postgres95ValueCreation) + +- stringValueForPostgres95Type:(NSString*)type + attribute:(EOAttribute*)attribute +{ + return @"NULL"; +} + +@end + + +@implementation NSObject (Postgres95ValueCreation) + +- stringValueForPostgres95Type:(NSString*)type + attribute:(EOAttribute*)attribute +{ + if ([self respondsToSelector:@selector(stringForType:)]) + return [[self stringForType:[attribute valueType]] + stringValueForPostgres95Type:type attribute:attribute]; + else if ([self respondsToSelector:@selector(dataForType:)]) + return [[self dataForType:[attribute valueType]] + stringValueForPostgres95Type:type attribute:attribute]; + else + THROW([[DataTypeMappingNotSupportedException alloc] + initWithFormat:@"Postgres95 cannot map value class %@ " + @"because its instances does not responds to either " + @" `stringForType:' or `dataForType:'. ", + NSStringFromClass([self class])]); + return nil; +} + +@end // NSObject (Postgres95ValueCreation) +*/ diff --git a/EOControl/EOAndQualifier.m b/EOControl/EOAndQualifier.m new file mode 100644 index 0000000..f06cd68 --- /dev/null +++ b/EOControl/EOAndQualifier.m @@ -0,0 +1,194 @@ +/** + EOAndQualifier.m EOAndQualifier Class + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + Author: Manuel Guesdon + Date: January 2002 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import +#import + +#import +#import +#import + +#import + + +@implementation EOAndQualifier + ++ (EOQualifier *)qualifierWithQualifierArray: (NSArray *)array +{ + return [[[self alloc] initWithQualifierArray: array] autorelease]; +} + ++ (EOQualifier *)qualifierWithQualifiers: (EOQualifier *)qualifiers, ... +{ + NSMutableArray *qualArray = [NSMutableArray array]; + EOQualifier *tmpId; + va_list ap; + + va_start(ap, qualifiers); + + for (tmpId = qualifiers; tmpId != nil;) + { + [qualArray addObject: tmpId]; + tmpId = va_arg(ap, id); + } + + va_end(ap); + + return [[[self alloc] initWithQualifierArray: qualArray] autorelease]; +} + +- (id) initWithQualifiers: (EOQualifier *)qualifiers, ... +{ + NSMutableArray *qualArray = [NSMutableArray array]; + EOQualifier *tmpId; + va_list ap; + + va_start(ap, qualifiers); + + for (tmpId = qualifiers; tmpId != nil;) + { + [qualArray addObject: tmpId]; + tmpId = va_arg(ap, id); + } + + va_end(ap); + + return [self initWithQualifierArray: qualArray]; +} + +- (id) initWithQualifierArray: (NSArray *)array +{ + if ((self = [self init])) + { + ASSIGN(_qualifiers, array); + } + + return self; +} + +- (void)dealloc +{ + DESTROY(_qualifiers); + + [super dealloc]; +} + +- (NSArray *)qualifiers +{ + return _qualifiers; +} + +- (id)copyWithZone: (NSZone *)zone +{ + EOAndQualifier *qual = [[EOAndQualifier allocWithZone: zone] init]; + + qual->_qualifiers = [_qualifiers copyWithZone: zone]; + + return qual; +} + +- (BOOL)evaluateWithObject: (id)object +{ + NSEnumerator *qualifiersEnum; + EOQualifier *qualifier; + + qualifiersEnum = [_qualifiers objectEnumerator]; + + while ((qualifier = [qualifiersEnum nextObject])) + { + if ([qualifier evaluateWithObject: object] == NO) + return NO; + } + + return YES; +} + +- (id) qualifierMigratedFromEntity: (id)param0 + relationshipPath: (id)param1 +{ + return [self notImplemented: _cmd]; //TODO +} + +- (void) _addBindingsToDictionary: (id)param0 +{ + [self notImplemented: _cmd]; //TODO +} + +- (EOQualifier *) qualifierWithBindings: (NSDictionary *)bindings + requiresAllVariables: (BOOL)requiresAllVariables +{ + EOFLOGObjectLevelArgs(@"EOQualifier", @"bindings=%@", bindings); + + if ([bindings count] > 0) + { + NSEmitTODO(); + return [self notImplemented: _cmd]; //TODO + } + else + return self; +} + +- (id) initWithKeyValueUnarchiver: (id)param0 +{ + return [self notImplemented: _cmd]; //TODO +} + +- (void) encodeWithKeyValueArchiver: (id)param0 +{ + [self notImplemented: _cmd]; //TODO +} + +- (id) validateKeysWithRootClassDescription: (id)param0 +{ + return [self notImplemented: _cmd]; //TODO +} + +- (id) description +{ + NSString *dscr; + + dscr = [NSString stringWithFormat: @"<%s %p - qualifiers: %@>", + object_get_class_name(self), + (void*)self, + _qualifiers]; + + return dscr; +} + +@end diff --git a/EOControl/EOCheapArray.h b/EOControl/EOCheapArray.h new file mode 100644 index 0000000..ecb3340 --- /dev/null +++ b/EOControl/EOCheapArray.h @@ -0,0 +1,86 @@ +/* + EOCheapArray.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: Sep 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOCheapArray_h__ +#define __EOCheapArray_h__ + +@interface EOCheapCopyArray : NSArray +{ + unsigned int _count; + id *_contents_array; + unsigned int _refcount; +} + +- (id) initWithArray: (id)array; +- (id) initWithObjects: (id*)objects + count: (unsigned int)count; +- (void) dealloc; +- (void) release; +- (unsigned int) retainCount; +- (id) retain; +- (id) objectAtIndex: (unsigned int)index; +//- (id) copyWithZone: (NSZone*)zone; +- (unsigned int) count; +//- (BOOL) containsObject: (id)obejct; + +@end + + +@interface EOCheapCopyMutableArray : NSMutableArray +{ + unsigned int _count; + id *_contents_array; + unsigned int _capacity; + unsigned int _grow_factor; + id _immutableCopy; +} + +- (id) initWithCapacity: (unsigned int)capacity; +- (id) initWithObjects: (id*)objects + count: (unsigned int)count; +- (id) initWithArray: (NSArray*)array; +- (void) dealloc; +- (id) shallowCopy; +- (void) _setCopy: (id)param0; +- (void) _mutate; +- (unsigned int) count; +- (id) objectAtIndex: (unsigned int)index; +- (void) addObject: (id)object; +- (void) insertObject: (id)object + atIndex: (unsigned int)index; +- (void) removeLastObject; +- (void) removeObjectAtIndex: (unsigned int)index; +- (void) replaceObjectAtIndex: (unsigned int)index + withObject: (id)object; +//- (BOOL) containsObject: (id)object; +//- (unsigned int) indexOfObjectIdenticalTo: (id)object; +//- (void) removeAllObjects; +- (void) exchangeObjectAtIndex: (unsigned int)index1 + withObjectAtIndex: (unsigned int)index2; +@end + + +#endif //__EOCheapArray_h__ diff --git a/EOControl/EOCheapArray.m b/EOControl/EOCheapArray.m new file mode 100644 index 0000000..8cf47a3 --- /dev/null +++ b/EOControl/EOCheapArray.m @@ -0,0 +1,446 @@ +/** + EOCheapArray.m EOCheapCopyArray Classes + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: Sep 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import + +#import +#import + + +@implementation EOCheapCopyArray : NSArray + +- (id) initWithArray: (id)array +{ + if ((self = [super initWithArray: array])) + { + } + + return self; +} + +- (id) initWithObjects: (id*)objects + count: (unsigned int)count +{ + if (count > 0) + { + unsigned i; + + _contents_array = NSZoneMalloc([self zone], sizeof(id) * count); + + if (_contents_array == 0) + { + RELEASE(self); + return nil; + } + + for (i = 0; i < count; i++) + { + if ((_contents_array[i] = RETAIN(objects[i])) == nil) + { + _count = i; + RELEASE(self); + [NSException raise: NSInvalidArgumentException + format: @"Tried to add nil"]; + } + } + + _count = count; + } + + return self; +} + +- (void) dealloc +{ + NSDebugMLLog(@"gsdb", @"Deallocate EOCheapCopyArray %p", self); + + if (_contents_array) + { +#if !GS_WITH_GC + unsigned i; + + for (i = 0; i < _count; i++) + { + [_contents_array[i] release]; + } +#endif + NSZoneFree([self zone], _contents_array); + } + + NSDeallocateObject(self); +} + +- (void) release +{ + NSDebugMLLog(@"gsdb", @"Release EOCheapCopyArray %p", self); + //TODO-NOW +} + +- (unsigned int) retainCount +{ + NSDebugMLLog(@"gsdb", @"retainCount EOCheapCopyArray %p", self); + //TODO-NOW + return 1; +} + +- (id) retain +{ + //TODO-NOW + NSDebugMLLog(@"gsdb", @"retain EOCheapCopyArray %p", self); + return self; +} + +- (id) objectAtIndex: (unsigned int)index +{ + if (index >= _count) + { + [NSException raise: NSRangeException + format: @"Index out of bounds"]; + } + + return _contents_array[index]; +} + +//- (id) copyWithZone: (NSZone*)zone; +- (unsigned int) count +{ + return _count; +} + +//- (BOOL) containsObject: (id)obejct; +@end + +@implementation EOCheapCopyMutableArray + +- (id) initWithCapacity: (unsigned int)capacity +{ + if (capacity == 0) + { + capacity = 1; + } + + _contents_array = NSZoneMalloc([self zone], sizeof(id) * capacity); + _capacity = capacity; + _grow_factor = capacity > 1 ? capacity/2 : 1; + + return self; +} + +- (id) initWithObjects: (id*)objects + count: (unsigned int)count +{ + self = [self initWithCapacity: count]; + + if (self != nil && count > 0) + { + unsigned i; + + for (i = 0; i < count; i++) + { + if ((_contents_array[i] = RETAIN(objects[i])) == nil) + { + _count = i; + RELEASE(self); + [NSException raise: NSInvalidArgumentException + format: @"Tried to add nil"]; + } + } + _count = count; + } + + return self; +} + +- (id) initWithArray:(NSArray*)array +{ + _grow_factor = 5; + + if ((self = [super initWithArray: array])) + { + } + + return self; +} + +- (void) dealloc +{ + NSDebugMLLog(@"gsdb", @"Deallocate EOCheapCopyArray %p", self); + + if (_contents_array) + { +#if !GS_WITH_GC + unsigned i; + for (i = 0; i < _count; i++) + { + [_contents_array[i] release]; + } +#endif + NSZoneFree([self zone], _contents_array); + } + + DESTROY(_immutableCopy); + NSDeallocateObject(self); +} + +- (id) shallowCopy +{ + //OK + if (!_immutableCopy) + { + _immutableCopy= [[EOCheapCopyArray alloc] + initWithObjects: _contents_array + count: _count]; + } + + return _immutableCopy; +} + +- (void) _setCopy: (id)param0 +{ + //TODO +} + +- (void) _mutate +{ + DESTROY(_immutableCopy); +} + +- (unsigned int) count +{ + return _count; +} + +- (id) objectAtIndex: (unsigned int)index +{ + if (index >= _count) + { + [NSException raise: NSRangeException + format: @"Index out of bounds"]; + } + + return _contents_array[index]; +} + +- (void)addObject: (id)object +{ +//7d0 +//im=530 + EOFLOGObjectFnStart(); + + NSDebugMLLog(@"gsdb", @"self %p=%@", self, self); + NSDebugMLLog(@"gsdb", @"object %p of class %@=%@", + object, + [object class], + object); + + if (!object) + { + [NSException raise: NSInvalidArgumentException + format: @"Tried to add nil"]; + } + + NSDebugMLLog(@"gsdb", @"self %p=%@", self, self); + + [self _mutate]; + + NSDebugMLLog(@"gsdb",@"self %p=%@", self, self); + + if (_count >= _capacity) + { + unsigned int grow = (_grow_factor>5 ? _grow_factor : 5); + size_t size = (_capacity + grow) * sizeof(id); + id *ptr; + + ptr = NSZoneRealloc([self zone], _contents_array, size); + + if (ptr == 0) + { + [NSException raise: NSMallocException + format: @"Unable to grow"]; + } + + _contents_array = ptr; + _capacity += _grow_factor; + _grow_factor = _capacity / 2; + } + + _contents_array[_count] = RETAIN(object); + _count++; // Do this AFTER we have retained the object. + + NSDebugMLLog(@"gsdb", @"self %p=%@", self, self); + + EOFLOGObjectFnStop(); +} + +- (void) insertObject: (id)object + atIndex: (unsigned int)index +{ + unsigned i; + + if (!object) + { + [NSException raise: NSInvalidArgumentException + format: @"Tried to insert nil"]; + } + + if (index > _count) + { + [NSException raise: NSRangeException + format: + @"in insertObject:atIndex:, index %d is out of range", + index]; + } + + [self _mutate]; + + if (_count == _capacity) + { + id *ptr; + size_t size = (_capacity + _grow_factor) * sizeof(id); + + ptr = NSZoneRealloc([self zone], _contents_array, size); + + if (ptr == 0) + { + [NSException raise: NSMallocException + format: @"Unable to grow"]; + } + + _contents_array = ptr; + _capacity += _grow_factor; + _grow_factor = _capacity / 2; + } + + for (i = _count; i > index; i--) + { + _contents_array[i] = _contents_array[i - 1]; + } + + /* + * Make sure the array is 'sane' so that it can be deallocated + * safely by an autorelease pool if the '[anObject retain]' causes + * an exception. + */ + _contents_array[index] = nil; + _count++; + _contents_array[index] = RETAIN(object); +} + +- (void) removeLastObject +{ + if (_count == 0) + { + [NSException raise: NSRangeException + format: @"Trying to remove from an empty array."]; + } + + [self _mutate]; + _count--; + + RELEASE(_contents_array[_count]); +} + +- (void) removeObjectAtIndex: (unsigned int)index +{ + id obj; + + if (index >= _count) + { + [NSException raise: NSRangeException + format: @"in removeObjectAtIndex:, index %d is out of range", + index]; + } + obj = _contents_array[index]; + [self _mutate]; + _count--; + + while (index < _count) + { + _contents_array[index] = _contents_array[index+1]; + index++; + } + + RELEASE(obj); /* Adjust array BEFORE releasing object. */ +} + +- (void) replaceObjectAtIndex: (unsigned int)index + withObject: (id)object; +{ + id obj; + + if (index >= _count) + { + [NSException raise: NSRangeException format: + @"in replaceObjectAtIndex:withObject:, index %d is out of range", + index]; + } + + /* + * Swap objects in order so that there is always a valid object in the + * array in case a retain or release causes an exception. + */ + obj = _contents_array[index]; + [self _mutate]; + + IF_NO_GC(RETAIN(object)); + _contents_array[index] = object; + + RELEASE(obj); +} + +//TODO implement it for speed ?? - (BOOL) containsObject:(id)object +//TODO implement it for speed ?? - (unsigned int) indexOfObjectIdenticalTo:(id)object +//TODO implement it for speed ?? - (void) removeAllObjects; +- (void) exchangeObjectAtIndex: (unsigned int)index1 + withObjectAtIndex: (unsigned int)index2 +{ + id obj = nil; + + if (index1 >= _count || index2>=_count) + { + [NSException raise: NSRangeException format: + @"in exchangeObjectAtIndex:withObjectAtIndex:, index %d is out of range", + (index1 >= _count ? index1 : index2)]; + } + + obj = _contents_array[index1]; + + [self _mutate]; + + _contents_array[index1] = _contents_array[index2]; + _contents_array[index2] = obj; +} + +@end diff --git a/EOControl/EOClassDescription.h b/EOControl/EOClassDescription.h new file mode 100644 index 0000000..e61c0ae --- /dev/null +++ b/EOControl/EOClassDescription.h @@ -0,0 +1,226 @@ +/* + EOClassDescription.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOClassDescription_h__ +#define __EOClassDescription_h__ + +#import +#import +#import + +@class NSDictionary; +@class NSFormatter; +@class EOEditingContext; +@class EOGlobalID; +@class EORelationship; + +typedef enum +{ + EODeleteRuleNullify = 0, + EODeleteRuleCascade, + EODeleteRuleDeny, + EODeleteRuleNoAction +} EODeleteRule; + +@interface EOClassDescription : NSObject + ++ (void)registerClassDescription: (EOClassDescription *)description + forClass: (Class)aClass; + ++ (void)invalidateClassDescriptionCache; + ++ (EOClassDescription *)classDescriptionForClass: (Class)aClass; + ++ (EOClassDescription *)classDescriptionForEntityName: (NSString *)entityName; + ++ (void)setClassDelegate: (id)delegate; ++ (id)classDelegate; + +// Must be implemented by subclasses. +- (NSString *)entityName; + +- (id)createInstanceWithEditingContext: (EOEditingContext *)editingContext + globalID: (EOGlobalID *)globalID + zone: (NSZone *)zone; + +- (void)awakeObject: (id)object +fromInsertionInEditingContext: (EOEditingContext *)editingContext; + +- (void)awakeObject: (id)object +fromFetchInEditingContext: (EOEditingContext *)editingContext; + +- (void)propagateDeleteForObject: (id)object + editingContext: (EOEditingContext *)editingContext; + +- (NSArray *)attributeKeys; +- (NSArray *)toOneRelationshipKeys; +- (NSArray *)toManyRelationshipKeys; +- (EORelationship *)relationshipNamed: (NSString *)relationshipName; +- (EORelationship *)anyRelationshipNamed: (NSString *)relationshipNamed; + +- (NSString *)inverseForRelationshipKey: (NSString *)relationshipKey; + +- (EODeleteRule)deleteRuleForRelationshipKey: (NSString *)relationshipKey; + +- (BOOL)ownsDestinationObjectsForRelationshipKey: (NSString *)relationshipKey; + +- (EOClassDescription *)classDescriptionForDestinationKey: (NSString *)detailKey; + +- (NSFormatter *)defaultFormatterForKey: (NSString *)key; + +- (NSString *)displayNameForKey: (NSString *)key; + +- (NSString *)userPresentableDescriptionForObject: (id)anObject; + +- (NSException *)validateValue: (id *)valueP forKey: (NSString *)key; + +- (NSException *)validateObjectForSave: (id)object; + +- (NSException *)validateObjectForDelete: (id)object; + +@end + + +@interface NSObject (EOInitialization) + +- initWithEditingContext: (EOEditingContext *)ec + classDescription: (EOClassDescription *)classDesc + globalID: (EOGlobalID *)globalID; + +@end + +@interface NSObject (EOClassDescriptionPrimitives) + +- (EOClassDescription *)classDescription; + +- (NSString *)entityName; +- (NSArray *)attributeKeys; +- (NSArray *)toOneRelationshipKeys; +- (NSArray *)toManyRelationshipKeys; +- (NSString *)inverseForRelationshipKey: (NSString *)relationshipKey; +- (EODeleteRule)deleteRuleForRelationshipKey: (NSString *)relationshipKey; +- (BOOL)ownsDestinationObjectsForRelationshipKey: (NSString *)relationshipKey; +- (EOClassDescription *)classDescriptionForDestinationKey: (NSString *)detailKey; + +- (NSString *)userPresentableDescription; + +- (NSException *)validateValue: (id *)valueP forKey: (NSString *)key; + +- (NSException *)validateForSave; + +- (NSException *)validateForDelete; + +- (void)awakeFromInsertionInEditingContext: (EOEditingContext *)editingContext; + +- (void)awakeFromFetchInEditingContext: (EOEditingContext *)editingContext; + +@end + +// Notifications: + +extern NSString *EOClassDescriptionNeededNotification; +extern NSString *EOClassDescriptionNeededForClassNotification; + +extern NSString *EOClassDescriptionNeededForEntityNameNotification; + + +@interface NSArray(EOShallowCopy) + +- (NSArray *)shallowCopy; + +@end + +@interface NSObject (EOClassDescriptionExtras) + +- (NSDictionary *)snapshot; + +- (void)updateFromSnapshot: (NSDictionary *)snapshot; + +- (BOOL)isToManyKey: (NSString *)key; + +- (NSException *)validateForInsert; +- (NSException *)validateForUpdate; + +- (NSArray *)allPropertyKeys; + +- (void)clearProperties; + +- (void)propagateDeleteWithEditingContext: (EOEditingContext *)editingContext; + +- (NSString *)eoShallowDescription; +- (NSString *)eoDescription; + +@end + +@interface NSObject (EOKeyRelationshipManipulation) + +- (void)addObject: object toPropertyWithKey: (NSString *)key; + +- (void)removeObject: object fromPropertyWithKey: (NSString *)key; + +- (void)addObject: object toBothSidesOfRelationshipWithKey: (NSString *)key; +- (void)removeObject: object +fromBothSidesOfRelationshipWithKey: (NSString *)key; + +@end + +// Validation exceptions (with name EOValidationException) +extern NSString *EOValidationException; +extern NSString *EOAdditionalExceptionsKey; +extern NSString *EOValidatedObjectUserInfoKey; +extern NSString *EOValidatedPropertyUserInfoKey; + +@interface NSException (EOValidationError) + ++ (NSException *)validationExceptionWithFormat: (NSString *)format, ...; ++ (NSException *)aggregateExceptionWithExceptions: (NSArray *)subexceptions; +- (NSException *)exceptionAddingEntriesToUserInfo: (NSDictionary *)additions; + +@end + +@interface NSObject (EOClassDescriptionClassDelegate) + +- (BOOL)shouldPropagateDeleteForObject: (id)object + inEditingContext: (EOEditingContext *)ec + forRelationshipKey: (NSString *)key; + +@end + + +@interface NSObject (_EOValueMerging) + +- (void)mergeValue: (id)value forKey: (id)key; +- (void)mergeChangesFromDictionary: (NSDictionary *)changes; +- (NSDictionary *)changesFromSnapshot: (NSDictionary *)snapshot; +- (void)reapplyChangesFromSnapshot: (NSDictionary *)changes; + +@end + +@interface NSObject (_EOEditingContext) +-(EOEditingContext*)editingContext; +@end + +#endif diff --git a/EOControl/EOClassDescription.m b/EOControl/EOClassDescription.m new file mode 100644 index 0000000..9417fb0 --- /dev/null +++ b/EOControl/EOClassDescription.m @@ -0,0 +1,1716 @@ +/** + EOClassDescription.m EOClassDescription Class + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + Author: Manuel Guesdon + Date: November 2001 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import + +#import +#import +#import +#import +#import +#import + + +//?? #define NOT_FOUND_CLASS_DESCRIPTION ([NSObject class]) //we use NSObject class as a "not found" value******* +@implementation EOClassDescription + + +NSString *EOClassDescriptionNeededNotification = @"EOClassDescriptionNeededNotification"; +NSString *EOClassDescriptionNeededForClassNotification = @"EOClassDescriptionNeededForClassNotification"; +NSString *EOClassDescriptionNeededForEntityNameNotification = @"EOClassDescriptionNeededForEntityNameNotification"; + +NSString *EOValidationException = @"EOValidationException"; +NSString *EOAdditionalExceptionsKey = @"EOAdditionalExceptionsKey"; +NSString *EOValidatedObjectUserInfoKey = @"EOValidatedObjectUserInfoKey"; +NSString *EOValidatedPropertyUserInfoKey = @"EOValidatedPropertyUserInfoKey"; + +/* + * Globals + */ + +static NSMapTable *classDescriptionForEntity = NULL; +static NSMapTable *classDescriptionForClass = NULL; +static id classDelegate = nil; + ++ (void)initialize +{ + classDescriptionForClass = NSCreateMapTable(NSObjectMapKeyCallBacks, + NSObjectMapValueCallBacks, + 32); + + classDescriptionForEntity = NSCreateMapTable(NSObjectMapKeyCallBacks, + NSObjectMapValueCallBacks, + 32); +} + + +/* + * Methods + */ + ++ (id)classDelegate +{ + return classDelegate; +} + ++ (EOClassDescription *)classDescriptionForClass:(Class)aClass +{ + EOClassDescription *classDescription; + + EOFLOGObjectFnStart(); + + NSDebugMLLog(@"gsdb", @"aClass=%@", aClass); + NSAssert(aClass, @"No class"); + NSDebugMLLog(@"gsdb", @"class name=%s", object_get_class_name(aClass)); + + classDescription = NSMapGet(classDescriptionForClass, aClass); + + NSDebugMLLog(@"gsdb", @"classDescription=%@", classDescription); +/* ?? if (classDescription==NOT_FOUND_CLASS_DESCRIPTION) + classDescription=nil; + else*/ + if (!classDescription) + { + [[NSNotificationCenter defaultCenter] + postNotificationName: EOClassDescriptionNeededForClassNotification + object: aClass]; + + classDescription = NSMapGet(classDescriptionForClass, aClass); + NSDebugMLLog(@"gsdb", @"classDescription=%@", classDescription); + + if (!classDescription) + { + NSLog(@"Warning: No class description for class named: %s", object_get_class_name(aClass)); + } + } + + EOFLOGObjectFnStop(); + + return classDescription; +} + ++ (EOClassDescription *)classDescriptionForEntityName: (NSString *)entityName +{ + EOClassDescription* classDescription; + + EOFLOGObjectFnStart(); + + NSDebugMLLog(@"gsdb", @"entityName=%@", entityName); + + classDescription = NSMapGet(classDescriptionForEntity, entityName); + NSDebugMLLog(@"gsdb",@"classDescription=%@",classDescription); + +/*?? if (classDescription==NOT_FOUND_CLASS_DESCRIPTION) + classDescription=nil; + else*/ + if (!classDescription) + { + [[NSNotificationCenter defaultCenter] + postNotificationName: EOClassDescriptionNeededForEntityNameNotification + object: entityName]; + + classDescription = NSMapGet(classDescriptionForEntity, entityName); + NSDebugMLLog(@"gsdb", @"classDescription=%@", classDescription); + + if (!classDescription) + { + NSLog(@"Warning: No class description for entity named: %@", entityName); + } + } + + EOFLOGObjectFnStop(); + + return classDescription; +} + ++ (void)setDelegate: (id)delegate +{ + EOFLOGObjectFnStart(); + + NSDebugMLLog(@"gsdb", @"delegate %p=%@", delegate, delegate); + + [EOClassDescription setClassDelegate: delegate]; + + EOFLOGObjectFnStop(); +} + ++ (id)delegate +{ + return [EOClassDescription classDelegate]; +} + ++ (void)invalidateClassDescriptionCache +{ + NSResetMapTable(classDescriptionForClass); + NSResetMapTable(classDescriptionForEntity); +} + ++ (void)registerClassDescription: (EOClassDescription *)description + forClass: (Class)aClass +{ + NSString *entityName; + + EOFLOGObjectFnStart(); + + NSAssert(description, @"No class description"); + NSAssert(aClass, @"No class"); + NSDebugMLLog(@"gsdb", @"description=%@", description); + + entityName = [description entityName]; + //NSAssert(entityName,@"No Entity Name"); + + NSMapInsert(classDescriptionForClass, aClass, description); + if (entityName) + { + NSMapInsert(classDescriptionForEntity, entityName, description); + } + + EOFLOGObjectFnStop(); +} + ++ (void)setClassDelegate:(id)delegate +{ + EOFLOGObjectFnStart(); + + NSDebugMLLog(@"gsdb",@"delegate %p=%@", delegate, delegate); + classDelegate = delegate; + + EOFLOGObjectFnStop(); +} + +- (NSArray *)attributeKeys +{ + return nil; +} + +- (void)awakeObject: (id)object +fromFetchInEditingContext: (EOEditingContext *)anEditingContext +{ + //OK + //nothing to do +} + +- (void)awakeObject: (id)object +fromInsertionInEditingContext: (EOEditingContext *)anEditingContext +{ + //Near OK + NSArray *toManyRelationshipKeys = [self toManyRelationshipKeys]; + int toManyCount = [toManyRelationshipKeys count]; + + if (toManyCount > 0) + { + int i; + + for (i = 0; i < toManyCount; i++) + { + id key = [toManyRelationshipKeys objectAtIndex: i]; + id value = [object storedValueForKey: key]; + + if (value) + { + //Do nothing ?? + } + else + { + [object takeStoredValue:[EOCheapCopyMutableArray + arrayWithCapacity: 2] + forKey: key]; + } + } + } +} + +- (EOClassDescription *)classDescriptionForDestinationKey: (NSString *)detailKey +{ + return nil; +} + +- (id)createInstanceWithEditingContext: (EOEditingContext *)anEditingContext + globalID: (EOGlobalID *)globalID + zone: (NSZone *)zone +{ + EOFLOGObjectFnStart(); + EOFLOGObjectFnStop(); + + return nil; +} + +- (NSFormatter *)defaultFormatterForKey: (NSString *)key +{ + return nil; +} + +- (NSFormatter *)defaultFormatterForKeyPath: (NSString *)keyPath +{ + return nil; //TODO +} + +- (EODeleteRule)deleteRuleForRelationshipKey: (NSString *)relationshipKey +{ + //OK + EOFLOGObjectFnStart(); + EOFLOGObjectFnStop(); + + return EODeleteRuleNullify; +} + +- (NSString *)displayNameForKey: (NSString *)key +{ + const char *s, *ckey = [key cString]; + NSMutableString *str = [NSMutableString initWithCapacity: [key length]]; + char c; + BOOL init = NO; + + s = ckey; + + while (*s) + { + if (init && s == ckey && islower(*s)) + { + c = toupper(*s); + [str appendString: [NSString stringWithCString: &c length: 1]]; + } + else if (isupper(*s) && s != ckey) + { + [str appendString: [NSString stringWithCString: ckey + length: s - ckey]]; + [str appendString: @" "]; + ckey = s; + } + + init = NO; + s++; + } + + if (s != ckey) + [str appendString: [NSString stringWithCString: ckey length: s - ckey]]; + + return [[key mutableCopy] autorelease]; +} + +- (NSString *)entityName +{ + //OK + return nil; +} + +- (NSString *)inverseForRelationshipKey: (NSString *)relationshipKey +{ + return nil; +} + +- (BOOL)ownsDestinationObjectsForRelationshipKey: (NSString *)relationshipKey +{ + return NO; +} + +- (void)propagateDeleteForObject: (id)object + editingContext: (EOEditingContext *)context +{ + NSArray *toRelArray; + NSEnumerator *toRelEnum; + NSString *key; //, *inverseKey = nil; + id destination = nil; + id classDelegate; + + EOFLOGObjectFnStart(); + + NSDebugMLLog(@"gsdb",@"object %p=%@", object, object); + + classDelegate = [EOClassDescription classDelegate]; + + NSDebugMLLog(@"gsdb", @"[EOClassDescription classDelegate]%p=%@", + classDelegate, + classDelegate); + + toRelArray = [object toOneRelationshipKeys]; + toRelEnum = [toRelArray objectEnumerator]; + + while ((key = [toRelEnum nextObject])) + { + BOOL shouldPropagate = YES; + + NSDebugMLLog(@"gsdb", @"ToOne key=%@", key); + + if (classDelegate) + shouldPropagate = [classDelegate shouldPropagateDeleteForObject: object + inEditingContext: context + forRelationshipKey: key]; + + NSDebugMLLog(@"gsdb", @"ToOne key=%@ shouldPropagate=%s", key, + (shouldPropagate ? "YES" : "NO")); + + if (shouldPropagate) + { + destination = [object storedValueForKey: key]; + NSDebugMLLog(@"gsdb", @"destination %p=%@", destination, destination); + + if (destination) + { + EODeleteRule deleteRule = [object deleteRuleForRelationshipKey: + key]; + + NSDebugMLLog(@"gsdb", @"deleteRule=%d", (int)deleteRule); + + switch (deleteRule) + { + case EODeleteRuleNullify: + NSDebugMLLog(@"gsdb", @"EODeleteRuleNullify"); + + [object removeObject: destination + fromBothSidesOfRelationshipWithKey: key]; + /* + [object takeValue:nil + forKey:key]; + inverseKey = [object inverseForRelationshipKey:key]; + NSDebugMLLog(@"gsdb",@"inverseKey=%@",inverseKey); + + if (inverseKey) + // p.ex. : the statement [employee inverseForRelationshipKey:@"department"] --> returns "employees" + [destination removeObject:object + fromPropertyWithKey:inverseKey]; + */ + break; + + case EODeleteRuleCascade: + //OK + NSDebugMLLog(@"gsdb", @"EODeleteRuleCascade"); + [object removeObject: destination + fromBothSidesOfRelationshipWithKey: key]; + [context deleteObject: destination]; + [destination propagateDeleteWithEditingContext: context]; + break; + + case EODeleteRuleDeny: + NSDebugMLLog(@"gsdb", @"EODeleteRuleDeny"); + // TODO don't know how to do yet, if raise an exception + // or something else. + NSEmitTODO(); + [self notImplemented: _cmd]; + break; + + case EODeleteRuleNoAction: + NSDebugMLLog(@"gsdb", @"EODeleteRuleNoAction"); + break; + } + } + } + } + + toRelArray = [self toManyRelationshipKeys]; + toRelEnum = [toRelArray objectEnumerator]; + + while ((key = [toRelEnum nextObject])) + { + BOOL shouldPropagate = YES; + + NSDebugMLLog(@"gsdb", @"ToMany key=%@", key); + + if (classDelegate) + shouldPropagate = [classDelegate shouldPropagateDeleteForObject: object + inEditingContext: context + forRelationshipKey: key]; + NSDebugMLLog(@"gsdb", @"ToMany key=%@ shouldPropagate=%s", key, + (shouldPropagate ? "YES" : "NO")); + + if (shouldPropagate) + { + NSArray *toManyArray; + EODeleteRule deleteRule; + + toManyArray = [object valueForKey: key]; + NSDebugMLLog(@"gsdb", @"toManyArray %p=%@", toManyArray, toManyArray); + + deleteRule = [object deleteRuleForRelationshipKey: key]; + NSDebugMLLog(@"gsdb", @"deleteRule=%d", (int)deleteRule); + + switch (deleteRule) + { + case EODeleteRuleNullify: + NSDebugMLLog(@"gsdb", @"EODeleteRuleNullify"); + NSDebugMLLog(@"gsdb", @"toManyArray %p=%@", toManyArray, + toManyArray); + + while ((destination = [toManyArray lastObject])) + { + NSDebugMLLog(@"gsdb", @"destination %p=%@", destination, + destination); + + [object removeObject: destination + fromBothSidesOfRelationshipWithKey: key]; + /* + inverseKey = [self inverseForRelationshipKey:key]; + NSDebugMLLog(@"gsdb",@"inverseKey=%@",inverseKey); + + if (inverseKey) + [destination removeObject:object + fromPropertyWithKey:inverseKey]; + */ + } + NSDebugMLLog(@"gsdb", @"toManyArray %p=%@", toManyArray, toManyArray); + break; + + case EODeleteRuleCascade: + //OK + NSDebugMLLog(@"gsdb", @"EODeleteRuleCascade"); + NSDebugMLLog(@"gsdb", @"toManyArray %p=%@", toManyArray, toManyArray); + + while ((destination = [toManyArray lastObject])) + { + NSDebugMLLog(@"gsdb", @"destination %p=%@", destination, destination); + + [object removeObject: destination + fromBothSidesOfRelationshipWithKey: key]; + [context deleteObject: destination]; + [destination propagateDeleteWithEditingContext: context]; + } + NSDebugMLLog(@"gsdb", @"toManyArray %p=%@", toManyArray, toManyArray); + break; + + case EODeleteRuleDeny: + NSDebugMLLog(@"gsdb", @"EODeleteRuleDeny"); + NSDebugMLLog(@"gsdb", @"toManyArray %p=%@", toManyArray, toManyArray); + if ([toManyArray count] > 0) + { + // TODO don't know how to do yet, if raise an exception + // or something else. + NSEmitTODO(); + [self notImplemented: _cmd]; + } + break; + + case EODeleteRuleNoAction: + NSDebugMLLog(@"gsdb", @"EODeleteRuleNoAction"); + break; + } + } + } + + EOFLOGObjectFnStop(); +} + +- (NSArray *)toManyRelationshipKeys +{ + //OK + return nil; +} + +- (NSArray *)toOneRelationshipKeys +{ + //OK + return nil; +} + +- (EORelationship *)relationshipNamed:(NSString *)relationshipName +{ + //OK + return nil; +} + +- (EORelationship *)anyRelationshipNamed:(NSString *)relationshipNamed +{ + return nil; +} + +- (NSString *)userPresentableDescriptionForObject:(id)anObject +{ + NSArray *attrArray = [self attributeKeys]; + NSEnumerator *attrEnum = [attrArray objectEnumerator]; + NSMutableString *values = [NSMutableString stringWithCapacity: + 4 * [attrArray count]]; + NSString *key; + BOOL init = YES; + + attrEnum = [attrArray objectEnumerator]; + + while ((key = [attrEnum nextObject])) + { + if (!init) + [values appendString: @","]; + + [values appendString: [[self valueForKey: key] description]]; + init = NO; + } + + return values; +} + +- (NSException *)validateObjectForDelete: (id)object +{ + return nil; +} + +- (NSException *)validateObjectForSave:(id)object +{ + return nil; +} + +- (NSException *)validateValue: (id *)valueP + forKey: (NSString *)key +{ + return nil; +} + +@end + + +@implementation NSObject (EOInitialization) + +- initWithEditingContext: (EOEditingContext *)ec + classDescription: (EOClassDescription *)classDesc + globalID: (EOGlobalID *)globalID; +{ + return [self init]; +} + +@end + + +@implementation NSObject (EOClassDescriptionPrimitives) + +// when you enable the NSDebugMLLogs here you will have a loop. dave +- (EOClassDescription *)classDescription +{ + EOClassDescription *cd; + + EOFLOGObjectFnStart(); + //NSDebugMLLog(@"gsdb", @"self (%p)=%@ class=%@", self, self, [self class]); + + cd = (EOClassDescription *)[EOClassDescription classDescriptionForClass: + [self class]]; + //NSDebugMLLog(@"gsdb", @"classDescription=%@", cd); + + EOFLOGObjectFnStop(); + + return cd; +} + +- (NSString *)entityName +{ + NSString *entityName; + + EOFLOGObjectFnStart(); + + entityName = [[self classDescription] entityName]; + + EOFLOGObjectFnStop(); + + return entityName; +} + +- (NSArray *)attributeKeys +{ + NSArray *attributeKeys; + + EOFLOGObjectFnStart(); + + attributeKeys = [[self classDescription] attributeKeys]; + + EOFLOGObjectFnStop(); + + return attributeKeys; +} + +- (NSArray *)toOneRelationshipKeys +{ + NSArray *toOneRelationshipKeys; + + EOFLOGObjectFnStart(); + + toOneRelationshipKeys = [[self classDescription] toOneRelationshipKeys]; + + EOFLOGObjectFnStop(); + + return toOneRelationshipKeys; +} + +- (NSArray *)toManyRelationshipKeys +{ + NSArray *toManyRelationshipKeys; + + EOFLOGObjectFnStart(); + + toManyRelationshipKeys = [[self classDescription] toManyRelationshipKeys]; + + EOFLOGObjectFnStop(); + + return toManyRelationshipKeys; +} + +- (NSString *)inverseForRelationshipKey: (NSString *)relationshipKey +{ + NSString *inverse; + + EOFLOGObjectFnStart(); + + inverse = [[self classDescription] + inverseForRelationshipKey: relationshipKey]; + + EOFLOGObjectFnStop(); + + return inverse; +} + +- (EODeleteRule)deleteRuleForRelationshipKey: (NSString *)relationshipKey +{ + EODeleteRule rule; + EOClassDescription *cd; + + EOFLOGObjectFnStart(); + NSDebugMLLog(@"gsdb", @"self %p=%@", self, self); + + cd = [self classDescription]; + NSDebugMLLog(@"gsdb", @"cd %p=%@", cd, cd); + + rule = [cd deleteRuleForRelationshipKey: relationshipKey]; + + EOFLOGObjectFnStop(); + + return rule; +} + +- (BOOL)ownsDestinationObjectsForRelationshipKey: (NSString *)relationshipKey +{ + BOOL owns; + + EOFLOGObjectFnStart(); + + owns = [[self classDescription] + ownsDestinationObjectsForRelationshipKey: relationshipKey]; + + EOFLOGObjectFnStop(); + + return owns; +} + +- (EOClassDescription *)classDescriptionForDestinationKey:(NSString *)detailKey +{ + EOClassDescription *cd; + + EOFLOGObjectFnStart(); + NSDebugMLLog(@"gsdb", @"detailKey=%@", detailKey); + + cd = [[self classDescription] classDescriptionForDestinationKey: detailKey]; + + EOFLOGObjectFnStop(); + + return cd; +} + +- (NSString *)userPresentableDescription +{ + NSString *userPresentableDescription = nil; + NSArray *attrArray; + NSEnumerator *attrEnum; + NSString *key; + + EOFLOGObjectFnStart(); + + attrArray = [self attributeKeys]; + attrEnum = [attrArray objectEnumerator]; + + while ((key = [attrEnum nextObject])) + { + if ([key isEqualToString: @"name"]) + return key; + } + + attrEnum = [attrArray objectEnumerator]; + while ((key = [attrEnum nextObject])) + { + if ([key isEqualToString: @"name"]) + return key; + } + + userPresentableDescription = [[self classDescription] + userPresentableDescription]; + + EOFLOGObjectFnStop(); + + return userPresentableDescription; +} + +- (NSException *)validateValue: (id *)valueP + forKey: (NSString *)key +{ + NSException *exception; + EOClassDescription *selfClassDescription; + + EOFLOGObjectFnStart(); + + NSAssert(valueP, @"No value pointer"); + NSDebugMLog(@"self (%p) [of class %@]=%@", self, [self class], self); + + selfClassDescription = [self classDescription]; + NSDebugMLog(@"selfClassDescription=%@",selfClassDescription); + + exception = [selfClassDescription validateValue: valueP + forKey: key]; + if (exception) + { + exception = [NSException exceptionWithName: [exception name] + reason: [exception reason] + userInfo: [NSDictionary + dictionaryWithObjectsAndKeys: + self, @"EOValidatedObjectUserInfoKey", + key, @"EOValidatedPropertyUserInfoKey", + nil, nil]]; + } + + if (exception == nil) + { + NSMutableString *selString = [NSMutableString stringWithCapacity: 32]; + SEL validateSelector; + const char *str; + char l; + + str = [key cString]; + l = str[0]; + + if (islower(l)) + l = toupper(l); + + [selString appendString: @"validate"]; + [selString appendString: [NSString stringWithCString: &l length: 1]]; + [selString appendString: [NSString stringWithCString: &str[1]]]; + [selString appendString: @":"]; + + validateSelector = NSSelectorFromString(selString); + + if (validateSelector && [self respondsToSelector: validateSelector]) + exception = [self performSelector: validateSelector + withObject: *valueP]; + } + + EOFLOGObjectFnStop(); + + return exception; +} + +- (NSException *)validateForSave +{ + NSMutableArray *expArray = nil; + NSException* exception; + int which; + + EOFLOGObjectFnStart(); + + exception = [[self classDescription] validateObjectForSave: self]; + + if (exception) + { + if (!expArray) + expArray = [NSMutableArray array]; + [expArray addObject:exception]; + } + + for (which = 0; which < 3; which++) + { + NSArray *keys; + + if (which == 0) + keys = [self attributeKeys]; + else if (which == 1) + keys = [self toOneRelationshipKeys]; + else + keys = [self toManyRelationshipKeys]; + + if (keys) + { + int keysCount = [keys count]; + int i; + + for (i = 0; i < keysCount; i++) + { + NSString *key = [keys objectAtIndex: i]; + id value = [self valueForKey: key]; + id newValue = value; + + exception = [self validateValue: &newValue + forKey: key]; + if (exception) + { + if (!expArray) + expArray = [NSMutableArray array]; + [expArray addObject: exception]; + } + + if ([newValue isEqual: value] == NO) + [self takeValue: newValue + forKey: key]; + } + } + } + + EOFLOGObjectFnStop(); + + return [NSException aggregateExceptionWithExceptions: expArray]; +} + +- (NSException *)validateForDelete +{ + NSException *exception; + + EOFLOGObjectFnStart(); + + exception = [[self classDescription] validateObjectForDelete: self]; + + EOFLOGObjectFnStop(); + + return exception; +} + +- (void)awakeFromInsertionInEditingContext: (EOEditingContext *)editingContext +{ + EOFLOGObjectFnStart(); + + [[self classDescription] awakeObject: self + fromInsertionInEditingContext: editingContext]; + + EOFLOGObjectFnStop(); +} + +- (void)awakeFromFetchInEditingContext: (EOEditingContext *)editingContext +{ + EOFLOGObjectFnStart(); + + [[self classDescription] awakeObject: self + fromFetchInEditingContext: editingContext]; + + EOFLOGObjectFnStop(); +} + +@end + + +@implementation NSArray (EOShallowCopy) + +- (NSArray *)shallowCopy +{ + return [[NSArray alloc] initWithArray: self]; +} + +@end + + +@implementation NSObject (EOClassDescriptionExtras) + +- (NSDictionary *)snapshot +{ + //OK Can be Improved may be by using a dictionaryinitializer + NSMutableDictionary *snapshot; + NSArray *attributeKeys; + NSArray *toOneRelationshipKeys; + NSArray *toManyRelationshipKeys; + + int attributeKeyCount; + int toOneRelationshipKeyCount; + int toManyRelationshipKeyCount; + EONull *null = (EONull *)[EONull null]; + int i; + + EOFLOGObjectFnStart(); + NSDebugMLLog(@"gsdb", @"self=%@", self); + + attributeKeys = [self attributeKeys]; + NSDebugMLLog(@"gsdb", @"attributeKeys=%@", attributeKeys); + + toOneRelationshipKeys = [self toOneRelationshipKeys]; + toManyRelationshipKeys = [self toManyRelationshipKeys]; + + attributeKeyCount = [attributeKeys count]; + toOneRelationshipKeyCount = [toOneRelationshipKeys count]; + toManyRelationshipKeyCount = [toManyRelationshipKeys count]; + + NSDebugMLLog(@"gsdb", @"attributeKeyCount=%d toOneRelationshipKeyCount=%d toManyRelationshipKeyCount=%d", + attributeKeyCount, toOneRelationshipKeyCount, + toManyRelationshipKeyCount); + + snapshot = [NSMutableDictionary dictionaryWithCapacity: attributeKeyCount + + toOneRelationshipKeyCount + + toManyRelationshipKeyCount]; + NSDebugMLLog(@"gsdb", @"attributeKeys=%@", attributeKeys); + + for (i = 0; i < attributeKeyCount; i++) + { + id key = [attributeKeys objectAtIndex: i]; + id value = [self storedValueForKey: key]; + + if (!value) + value = null; + + NSDebugMLLog(@"gsdb", @"snap=%p key=%@ ==> value %p=%@", + snapshot, key, value, value); + [snapshot setObject: value + forKey: key]; + } + + NSDebugMLLog(@"gsdb", @"toOneRelationshipKeys=%@", toOneRelationshipKeys); + + for (i = 0; i < toOneRelationshipKeyCount; i++) + { + id key = [toOneRelationshipKeys objectAtIndex: i]; + id value = [self storedValueForKey: key]; + + if (!value) + value = null; + + NSDebugMLLog(@"gsdb", @"TOONE snap=%p key=%@ ==> value %p=%@", + snapshot, key, value, value); + + [snapshot setObject: value + forKey: key]; + } + + NSDebugMLLog(@"gsdb",@"toManyRelationshipKeys=%@",toManyRelationshipKeys); + + for (i = 0; i < toManyRelationshipKeyCount; i++) + { + id key = [toManyRelationshipKeys objectAtIndex: i]; + id value = [self storedValueForKey: key]; + + if (value) + { + NSDebugMLLog(@"gsdb", @"TOMANY snap=%p key=%@ ==> value %p=%@", + snapshot, key, value, value); + + value = [value shallowCopy]; + NSDebugMLLog(@"gsdb", @"TOMANY snap=%p key=%@ ==> value %p=%@", + snapshot, key, value, value); + + [snapshot setObject: value + forKey: key]; + } + /* //TODO-VERIFY or set it to eonull ? + else + value=null; + */ + } + + NSDebugMLLog(@"gsdb", @"self=%p snapshot=%p", self, snapshot); + NSDebugMLLog(@"gsdb", @"self %p=%@\nsnapshot %p=%@", self, self, snapshot, + snapshot); + + EOFLOGObjectFnStop(); + + NSDebugMLLog(@"gsdb", @"self=%p snapshot=%p count=%d", + self, snapshot, [snapshot count]); + + return snapshot; +} + +- (void)updateFromSnapshot: (NSDictionary *)snapshot +{ + NSEnumerator *snapshotEnum = [snapshot keyEnumerator]; + NSString *key; + EONull *null = (EONull *)[EONull null]; + id val; + + while ((key = [snapshotEnum nextObject])) + { + val = [snapshot objectForKey: key]; + + if ([val isEqual: null]) + val = nil; + + if ([val isKindOfClass: [NSArray class]]) + val = [[[val shallowCopy] autorelease] mutableCopy]; + + [self takeStoredValue: val forKey: key]; + } +} + +- (BOOL)isToManyKey: (NSString *)key +{ + NSArray *toMany = [self toManyRelationshipKeys]; + NSEnumerator *toManyEnum = [toMany objectEnumerator]; + NSString *relationship; + + while ((relationship = [toManyEnum nextObject])) + { + if ([relationship isEqualToString: key]) + return YES; + } + + return NO; +} + +- (NSException *)validateForInsert +{ + NSException *exception; + + EOFLOGObjectFnStart(); + + exception = [self validateForSave]; + + EOFLOGObjectFnStop(); + + return exception; +} + +- (NSException *)validateForUpdate +{ + NSException *exception; + + EOFLOGObjectFnStart(); + + exception = [self validateForDelete]; + + EOFLOGObjectFnStop(); + + return exception; +} + +- (NSArray *)allPropertyKeys +{ + NSArray *toOne; + NSArray *toMany; + NSArray *attr; + NSMutableArray *ret; + + attr = [self attributeKeys]; + toOne = [self toOneRelationshipKeys]; + toMany = [self toManyRelationshipKeys]; + + ret = [NSMutableArray arrayWithCapacity: + [attr count] + + [toOne count] + [toMany count]]; + + [ret addObjectsFromArray: attr]; + [ret addObjectsFromArray: toOne]; + [ret addObjectsFromArray: toMany]; + + return ret; +} + +- (void)clearProperties +{ + NSArray *toOne = [self toOneRelationshipKeys]; + NSArray *toMany = [self toManyRelationshipKeys]; + NSEnumerator *relEnum; + NSString *key; + + relEnum = [toOne objectEnumerator]; + while ((key = [relEnum nextObject])) + [self takeStoredValue: nil forKey: key]; + + relEnum = [toMany objectEnumerator]; + while ((key = [relEnum nextObject])) + [self takeStoredValue: nil forKey: key]; +} + +- (void)propagateDeleteWithEditingContext: (EOEditingContext *)editingContext +{ + EOFLOGObjectFnStart(); + + [[self classDescription] propagateDeleteForObject: self + editingContext: editingContext]; + + EOFLOGObjectFnStop(); +} + +- (NSString *)eoShallowDescription +{ + [self notImplemented: _cmd]; + return nil; //TODO +} + +- (NSString *)eoDescription +{ + NSArray *attrArray = [self allPropertyKeys]; + NSEnumerator *attrEnum = [attrArray objectEnumerator]; + NSString *key; + NSMutableString *ret = [NSMutableString + stringWithCapacity: 5 * [attrArray count]]; + + [ret appendString: [NSString stringWithFormat:@"<%@ (%p)", + NSStringFromClass([self class]), self]]; + + while ((key = [attrEnum nextObject])) + { + [ret appendString: [NSString stringWithFormat: @" %@=%@", + key, [self valueForKey: key]]]; + } + + [ret appendString: [NSString stringWithFormat: @">"]]; + + return ret; //TODO +} + +@end + + +@implementation NSObject (EOKeyRelationshipManipulation) + +- (void)addObject: object +toPropertyWithKey: (NSString *)key +{ + const char *str = NULL; + + EOFLOGObjectFnStart(); + NSDebugMLLog(@"gsdb", @"self=%@", self); + NSDebugMLLog(@"gsdb", @"object=%@", object); + NSDebugMLLog(@"gsdb", @"key=%@", key); + + str = [key cString]; + + NSDebugMLLog(@"gsdb", @"*+* ciao3 %@", key); + NSDebugMLLog(@"gsdb", @"*+* ciao3 %@", object); + + if ([key length]) + { + NSMutableString *selString = [NSMutableString stringWithCapacity: 25]; + SEL addToSelector; + char l = str[0]; + + if (islower(l)) + l = toupper(l); + + [selString appendString: @"addTo"]; + [selString appendString: [NSString stringWithCString: &l length: 1]]; + [selString appendString: [NSString stringWithCString: &str[1]]]; + [selString appendString: @":"]; + + addToSelector = NSSelectorFromString(selString); + + if (addToSelector && [self respondsToSelector: addToSelector] == YES) + { + NSDebugMLLog(@"gsdb", @"selector=%@", selString); + + [self performSelector: addToSelector + withObject: object]; + } + else + { + id val = nil; + + if ([self isToManyKey: key] == YES) + { + NSDebugMLLog(@"gsdb", @"to many"); + + val = [self valueForKey: key]; //should use storedValueForKey: ? + + NSDebugMLLog(@"gsdb", @"to many val=%@ (%@)", val, [val class]); + + if ([val containsObject: object]) + { + NSDebugMLog(@"Object %p already in too many val=%@ (%@)", + object, val, [val class]); + } + else + { + if ([val isKindOfClass: [NSMutableArray class]]) + { + NSDebugMLLog(@"gsdb", @"to many2"); + [self willChange]; + [val addObject: object]; + } + else + { + NSMutableArray *relArray; + + if (val) + relArray = [[val mutableCopy] autorelease]; + else + relArray = [NSMutableArray arrayWithCapacity: 10]; + + NSDebugMLLog(@"gsdb", @"relArray=%@ (%@)", + relArray, [relArray class]); + + [relArray addObject: object]; + NSDebugMLLog(@"gsdb", @"relArray=%@ (%@)", + relArray, [relArray class]); + + [self takeValue: relArray + forKey: key]; + } + } + } + else + { + NSDebugMLLog(@"gsdb", @"key is not to many"); + + [self takeValue: object + forKey: key]; + } + } + } + + NSDebugMLLog(@"gsdb", @"self=%@", self); + NSDebugMLLog(@"gsdb", @"object=%@", object); + + EOFLOGObjectFnStop(); +} + +- (void)removeObject: object + fromPropertyWithKey: (NSString *)key +{ +//self valueForKey: + const char *str = NULL; + + EOFLOGObjectFnStart(); + NSDebugMLLog(@"gsdb", @"self=%@", self); + NSDebugMLLog(@"gsdb", @"object=%@", object); + NSDebugMLLog(@"gsdb", @"key=%@ class=%@", key, [key class]); + + str = [key cString]; + + if ([key length]) + { + NSMutableString *selString = [NSMutableString stringWithCapacity: 25]; + SEL removeFromSelector; + char l = str[0]; + + if (islower(l)) + l = toupper(l); + + [selString appendString: @"removeFrom"]; + NSDebugMLLog(@"gsdb", @"selString=%@", selString); + [selString appendString: [NSString stringWithCString: &l + length: 1]]; + NSDebugMLLog(@"gsdb", @"selString=%@", selString); + [selString appendString: [NSString stringWithCString: &str[1]]]; + NSDebugMLLog(@"gsdb", @"selString=%@", selString); + [selString appendString: @":"]; + NSDebugMLLog(@"gsdb", @"selString=%@", selString); + + removeFromSelector = NSSelectorFromString(selString); + + NSDebugMLLog(@"gsdb", @"selString=%@ removeFromSelector=%p", selString, + (void*)removeFromSelector); + + if (removeFromSelector && [self respondsToSelector: removeFromSelector]) + { + NSDebugMLLog(@"gsdb", @"responds=YES"); + [self performSelector: removeFromSelector + withObject: object]; + } + else + { + id val = nil; + + NSDebugMLLog(@"gsdb", @"responds=NO"); + + if ([self isToManyKey:key] == YES) + { + NSDebugMLLog(@"gsdb", @"key is to many"); + + val = [self valueForKey: key]; + NSDebugMLLog(@"gsdb", @"val=%@", val); + + if ([val isKindOfClass: [NSMutableArray class]]) + { + [self willChange]; + [val removeObject: object]; + } + else + { + NSMutableArray *relArray = nil; + + if (val) + { + relArray = [[val mutableCopy] autorelease]; + + [relArray removeObject: object]; + [self takeValue: relArray + forKey: key]; + } + } + } + else + { + NSDebugMLLog(@"gsdb", @"key is not to many"); + [self takeValue: nil + forKey: key]; + } + } + } + + NSDebugMLLog(@"gsdb", @"self=%@", self); + NSDebugMLLog(@"gsdb", @"object=%@", object); + + EOFLOGObjectFnStop(); +} + +-(void)_setObject: (id)object +forBothSidesOfRelationshipWithKey: (NSString*)key +{ + //Near OK + NSString *inverseKey; + id oldObject; + + EOFLOGObjectFnStart(); + NSDebugMLLog(@"gsdb", @"self=%@", self); + NSDebugMLLog(@"gsdb", @"object=%@", object); + NSDebugMLLog(@"gsdb", @"key=%@", key); + + inverseKey = [self inverseForRelationshipKey:key]; + NSDebugMLLog(@"gsdb", @"inverseKey=%@", inverseKey); + + oldObject = [self valueForKey: key]; + NSDebugMLLog(@"gsdb", @"oldObject=%@", oldObject); + + if (inverseKey) + { + [oldObject removeObject: self + fromPropertyWithKey: inverseKey]; + [object addObject: self + toPropertyWithKey: inverseKey]; +/* if ([object isToManyKey:inverseKey]) + { + //?? + NSDebugMLLog(@"gsdb",@"Inverse is to many"); + [oldObject removeObject:self + fromPropertyWithKey:inverseKey]; + [object addObject:self + toPropertyWithKey:inverseKey]; + } + else + { + NSDebugMLLog(@"gsdb",@"Inverse is not to many"); + //OK + //MIRKO if ((inverseKey = [oldObject inverseForRelationshipKey:key])) + //MIRKO [oldObject removeObject:self + // fromPropertyWithKey:inverseKey]; + [oldObject takeValue:nil + forKey:inverseKey]; + [object takeValue:self + forKey:inverseKey]; + }; +*/ + } + + [self takeValue: object + forKey: key]; + + NSDebugMLLog(@"gsdb", @"self=%@", self); + NSDebugMLLog(@"gsdb", @"object=%@", object); + + EOFLOGObjectFnStop(); +} + +- (void)addObject: (id)object +toBothSidesOfRelationshipWithKey: (NSString *)key +{ + EOFLOGObjectFnStart(); + + NSDebugMLLog(@"gsdb", @"self=%@", self); + NSDebugMLLog(@"gsdb", @"object=%@", object); + NSDebugMLLog(@"gsdb", @"key=%@", key); + + // 2 differents cases: to-one and to-many relation + if ([self isToManyKey:key]) // to-many + { + //See if there's an inverse relationship + NSString *inverseKey = [self inverseForRelationshipKey: key]; + + NSDebugMLLog(@"gsdb", @"self %p=%@,object %p=%@ key=%@ inverseKey=%@", + self, + self, + object, + object, + key, + inverseKey); + + // First add object to self relation array + [self addObject: object + toPropertyWithKey: key]; + + if (inverseKey) //if no inverse relation do nothing + { + // See if inverse relationship is to-many or to-one + if ([object isToManyKey: inverseKey]) + { + NSEmitTODO(); + [self notImplemented:_cmd]; + } + else + { + // Previous value, if any + id oldObject = [object valueForKey: inverseKey]; + + NSDebugMLLog(@"gsdb", @"oldObject=%@", oldObject); + + if (oldObject) + { + //TODO self removeObject:oldObject fromPropertyWithKey:key + NSEmitTODO(); + [self notImplemented:_cmd]; + } + + // Just set self into object relationship property + [object takeValue: self + forKey: inverseKey]; + } + } + } + else + { + [self _setObject: object + forBothSidesOfRelationshipWithKey: key]; + } + + NSDebugMLLog(@"gsdb", @"self=%@", self); + NSDebugMLLog(@"gsdb", @"object=%@", object); + + EOFLOGObjectFnStop(); +} + +- (void)removeObject: (id)object +fromBothSidesOfRelationshipWithKey: (NSString *)key +{ + NSString *inverseKey; + + [self removeObject: object + fromPropertyWithKey: key]; + + if ((inverseKey = [self inverseForRelationshipKey: key])) + [object removeObject: self + fromPropertyWithKey: inverseKey]; +} + +@end + + +@implementation NSException (EOValidationError) + ++ (NSException *)validationExceptionWithFormat: (NSString *)format, ... +{ + NSException *exp; + NSString *name; + va_list args; + + va_start(args, format); + + name = [[[NSString alloc] initWithFormat: format arguments: args] + autorelease]; + exp = [NSException exceptionWithName: EOValidationException + reason: name + userInfo: nil]; + + va_end(args); + + return exp; +} + ++ (NSException *)aggregateExceptionWithExceptions: (NSArray *)subexceptions +{ + NSException *exp = nil; + + if ([subexceptions count] == 1) + exp = [subexceptions objectAtIndex: 0]; + else if ([subexceptions count] > 1) + { + NSString *name, *reason; + NSMutableDictionary *userInfo; + + exp = [subexceptions objectAtIndex: 0]; + + name = [exp name]; + reason = [exp reason]; + userInfo = [[exp userInfo] mutableCopy]; + + [userInfo setObject: subexceptions + forKey: EOAdditionalExceptionsKey]; + + exp = [NSException exceptionWithName: name + reason: reason + userInfo: userInfo]; + } + + return exp; +} + +- (NSException *)exceptionAddingEntriesToUserInfo: (NSDictionary *)additions +{ + NSException *exp; + NSString *name, *reason; + NSMutableDictionary *userInfo; + + name = [self name]; + reason = [self reason]; + userInfo = [[self userInfo] mutableCopy]; + + [userInfo setObject: [additions allValues] + forKey: EOValidatedObjectUserInfoKey]; + [userInfo setObject: [additions allKeys] + forKey: EOValidatedPropertyUserInfoKey]; + + exp = [NSException exceptionWithName: name + reason: reason + userInfo: userInfo]; + + return exp; +} + +@end + + +@implementation NSObject (EOClassDescriptionClassDelegate) + +- (BOOL)shouldPropagateDeleteForObject: (id)object + inEditingContext: (EOEditingContext *)ec + forRelationshipKey: (NSString *)key +{ + return YES; +} + +@end + + +@implementation NSObject (_EOValueMerging) + +- (void)mergeValue: (id)value + forKey: (id)key +{ + [self notImplemented:_cmd]; + return; +} + +- (void)mergeChangesFromDictionary: (NSDictionary *)changes +{ + [self notImplemented:_cmd]; + return; +} + +- (NSDictionary *)changesFromSnapshot: (NSDictionary *)snapshot +{ + id propertiesList[2]; + NSArray *properties; + int h, i, count; + NSMutableArray *newKeys = [NSMutableArray arrayWithCapacity: 16]; + NSMutableArray *newVals = [NSMutableArray arrayWithCapacity: 16]; + NSString *key; + + propertiesList[0] = [self attributeKeys]; + propertiesList[1] = [self toOneRelationshipKeys]; + + for (h = 0; h < 2; h++) + { + id val, oldVal; + + properties = propertiesList[h]; + count = [properties count]; + + for(i = 0; i < count; i++) + { + key = [properties objectAtIndex: i]; + val = [self storedValueForKey: key]; + oldVal = [snapshot storedValueForKey: key]; + + if (val == oldVal || [val isEqual: oldVal] == YES) + continue; + + [newKeys addObject: key]; + [newVals addObject: val]; + } + } + + properties = [self toManyRelationshipKeys]; + count = [properties count]; + + for(i = 0; i < count; i++) + { + NSMutableArray *array, *objects; + NSArray *val, *oldVal; + int valCount, oldValCount; + + key = [properties objectAtIndex: i]; + val = [self storedValueForKey: key]; + oldVal = [snapshot objectForKey: key]; + + if ((id)val == [EONull null]) + val = nil; + + if ((id)oldVal == [EONull null]) + oldVal = nil; + + if (!val && !oldVal) + continue; + + valCount = [val count]; + oldValCount = [oldVal count]; + + if (valCount == 0 && oldValCount == 0) + continue; + + array = [NSMutableArray arrayWithCapacity: 2]; + if (val && valCount>0) + { + objects = [NSMutableArray arrayWithArray: val]; + [objects removeObjectsInArray: oldVal]; + } + else + objects = [NSMutableArray arrayWithCapacity: 1]; + + [array addObject: objects]; + + if (val && valCount > 0) + { + objects = [NSMutableArray arrayWithArray: oldVal]; + [objects removeObjectsInArray: val]; + } + else + objects = [NSMutableArray arrayWithCapacity: 1]; + + [array addObject: objects]; + + [newKeys addObject: key]; + [newVals addObject: array]; + } + + return [NSDictionary dictionaryWithObjects: newVals forKeys: newKeys]; +} + +- (void)reapplyChangesFromSnapshot: (NSDictionary *)changes +{ + [self notImplemented: _cmd]; +} + +@end + +@implementation NSObject (_EOEditingContext) + +-(EOEditingContext*)editingContext +{ + return [EOObserverCenter observerForObject: self + ofClass: [EOEditingContext class]]; +} + +@end + diff --git a/EOControl/EOControl.h b/EOControl/EOControl.h new file mode 100644 index 0000000..e3bc293 --- /dev/null +++ b/EOControl/EOControl.h @@ -0,0 +1,52 @@ +/* + EOControl.h + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOControl_h__ +#define __EOControl_h__ + + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + + +#endif /* __EOControl_h__ */ + diff --git a/EOControl/EODataSource.h b/EOControl/EODataSource.h new file mode 100644 index 0000000..ced34d2 --- /dev/null +++ b/EOControl/EODataSource.h @@ -0,0 +1,63 @@ +/* + EODataSource.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: July 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EODataSource_h__ +#define __EODataSource_h__ + +#import + +@class NSArray; +@class NSDictionary; +@class EOEditingContext; +@class EOClassDescription; + + +@interface EODataSource : NSObject + +- (id)createObject; + +- (void)insertObject: object; + +- (void)deleteObject: object; + +- (NSArray *)fetchObjects; + +- (EOEditingContext *)editingContext; + +- (void)qualifyWithRelationshipKey: (NSString *)key ofObject: sourceObject; + +- (EODataSource *)dataSourceQualifiedByKey: (NSString *)key; + +- (EOClassDescription *)classDescriptionForObjects; + +- (NSArray *)qualifierBindingKeys; + +- (void)setQualifierBindings: (NSDictionary *)bindings; +- (NSDictionary *)qualifierBindings; + +@end + +#endif diff --git a/EOControl/EODataSource.m b/EOControl/EODataSource.m new file mode 100644 index 0000000..6062b34 --- /dev/null +++ b/EOControl/EODataSource.m @@ -0,0 +1,119 @@ +/** + EODataSource.m EODataSource Class + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: July 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import +#import +#import + +@implementation EODataSource + +- (id)createObject +{ + id object; + EOClassDescription *cd; + EOEditingContext *receiverEdCtxt; + + EOFLOGObjectFnStart(); + + cd = [self classDescriptionForObjects]; + EOFLOGObjectLevelArgs(@"EODataSource", @"cd=%@", cd); + + object = [cd createInstanceWithEditingContext: nil + globalID: nil + zone: NULL]; + + EOFLOGObjectLevelArgs(@"EODataSource", @"object=%@", object); + + if (object && (receiverEdCtxt = [self editingContext])) + [receiverEdCtxt insertObject: object]; + + EOFLOGObjectFnStop(); + + return object; +} + +- (void)insertObject: object +{ + [self subclassResponsibility: _cmd]; +} + +- (void)deleteObject: object +{ + [self subclassResponsibility: _cmd]; +} + +- (NSArray *)fetchObjects +{ + return nil; +} + +- (EOEditingContext *)editingContext +{ + return nil; +} + +- (void)qualifyWithRelationshipKey: (NSString *)key ofObject: sourceObject +{ + [self subclassResponsibility: _cmd]; +} + +- (EODataSource *)dataSourceQualifiedByKey: (NSString *)key +{ + [self subclassResponsibility: _cmd]; + + return nil; +} + +- (EOClassDescription *)classDescriptionForObjects +{ + return nil; +} + +- (NSArray *)qualifierBindingKeys +{ + return nil; +} + +- (void)setQualifierBindings: (NSDictionary *)bindings +{ +} + +- (NSDictionary *)qualifierBindings +{ + return nil; +} + +@end diff --git a/EOControl/EODebug.h b/EOControl/EODebug.h new file mode 100644 index 0000000..98b7dff --- /dev/null +++ b/EOControl/EODebug.h @@ -0,0 +1,266 @@ +/* debug.h - debug + Copyright (C) 1999 Free Software Foundation, Inc. + + Written by: Manuel Guesdon + Date: Jan 1999 + + This file is part of the GNUstep Web Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +// $Id$ + +#ifndef _EODebug_h__ +#define _EODebug_h__ + +// call with --GNU-Debug=EOFFn + +#ifdef DEBUG + +#include +#include + +extern void EOFLogC_(const char* file,int line,const char* string); +extern void EOFLogDumpObject_(const char* file,int line,id object,int deep); +extern void EOFLogAssertGood_(const char* file,int line,NSObject* object); + +#define EOFLogC(cString); EOFLogC_(__FILE__,__LINE__,cString); +#define EOFLogDumpObject(object,deep); EOFLogDumpObject_(__FILE__,__LINE__,object,deep); +#define EOFLogAssertGood(object); EOFLogAssertGood_(__FILE__,__LINE__,object); +#else // no DEBUG +#define EOFLogC(cString); +#define EOFLogDumpObject(object,deep); +#define EOFLogAssertGood(object); +#endif // DEBUG + + +#ifdef DEBUG + +// call in Class-Methods + +#define EOFLOGClassFnStart() \ + do { if (GSDebugSet(@"EOFFn") == YES) { \ + NSAutoreleasePool *tmpPool = [NSAutoreleasePool new]; \ + NSString *fmt = GSDebugFunctionMsg(__PRETTY_FUNCTION__, __FILE__, __LINE__,@"FNSTART"); \ + NSLog(fmt); [tmpPool release]; }} while (0) + +#define EOFLOGObjectFnStartCond(cond) \ + do { if ((GSDebugSet(@"EOFFn") == YES) && GSDebugSet(cond) == YES) { \ + NSAutoreleasePool *tmpPool = [NSAutoreleasePool new]; \ + NSString *fmt = GSDebugMethodMsg(self, _cmd, __FILE__, __LINE__,@"FNSTART"); \ + NSLog(fmt); [tmpPool release]; }} while (0) + +#define EOFLOGClassFnStartOrCond(cond) \ + do { if ((GSDebugSet(@"EOFFn") == YES) || (GSDebugSet(cond) == YES)) { \ + NSAutoreleasePool *tmpPool = [NSAutoreleasePool new]; \ + NSString *fmt = GSDebugFunctionMsg(__PRETTY_FUNCTION__, __FILE__, __LINE__,@"FNSTART"); \ + NSLog(fmt); [tmpPool release]; }} while (0) + +#define EOFLOGClassFnStartOrCond2(cond1,cond2) \ + do { if ((GSDebugSet(@"EOFFn") == YES) || (GSDebugSet(cond1) == YES) || (GSDebugSet(cond2) == YES)) { \ + NSAutoreleasePool *tmpPool = [NSAutoreleasePool new]; \ + NSString *fmt = GSDebugFunctionMsg(__PRETTY_FUNCTION__, __FILE__, __LINE__,@"FNSTART"); \ + NSLog(fmt); [tmpPool release]; }} while (0) + +#define EOFLOGClassFnStop() \ + do { if (GSDebugSet(@"EOFFn") == YES) { \ + NSAutoreleasePool *tmpPool = [NSAutoreleasePool new]; \ + NSString *fmt = GSDebugFunctionMsg(__PRETTY_FUNCTION__,__FILE__, __LINE__,@"FNSTOP"); \ + NSLog(fmt); [tmpPool release]; }} while (0) + +#define EOFLOGObjectFnStopCond(cond) \ + do { if ((GSDebugSet(@"EOFFn") == YES) && GSDebugSet(cond) == YES) { \ + NSAutoreleasePool *tmpPool = [NSAutoreleasePool new]; \ + NSString *fmt = GSDebugMethodMsg(self, _cmd, __FILE__, __LINE__,@"FNSTOP"); \ + NSLog(fmt); [tmpPool release]; }} while (0) + +#define EOFLOGClassFnStopOrCond(cond) \ + do { if ((GSDebugSet(@"EOFFn") == YES) || (GSDebugSet(cond) == YES)) { \ + NSAutoreleasePool *tmpPool = [NSAutoreleasePool new]; \ + NSString *fmt = GSDebugFunctionMsg(__PRETTY_FUNCTION__,__FILE__, __LINE__,@"FNSTOP"); \ + NSLog(fmt); [tmpPool release]; }} while (0) + +#define EOFLOGClassFnStopOrCond2(cond1,cond2) \ + do { if ((GSDebugSet(@"EOFFn") == YES) || (GSDebugSet(cond1) == YES) || (GSDebugSet(cond2) == YES)) { \ + NSAutoreleasePool *tmpPool = [NSAutoreleasePool new]; \ + NSString *fmt = GSDebugFunctionMsg(__PRETTY_FUNCTION__,__FILE__, __LINE__,@"FNSTOP"); \ + NSLog(fmt); [tmpPool release]; }} while (0) + +#define EOFLOGClassLevel(level,format) \ + do { if (GSDebugSet(level) == YES) { \ + NSAutoreleasePool *tmpPool = [NSAutoreleasePool new]; \ + NSString *fmt = GSDebugFunctionMsg( \ + __PRETTY_FUNCTION__, __FILE__, __LINE__, format); \ + NSLog(fmt); [tmpPool release]; }} while (0) + +#define EOFLOGClassLevelArgs(level, format, args...) \ + do { if (GSDebugSet(level) == YES) { \ + NSAutoreleasePool *tmpPool = [NSAutoreleasePool new]; \ + NSString *fmt = GSDebugFunctionMsg( \ + __PRETTY_FUNCTION__, __FILE__, __LINE__, format); \ + NSLog(fmt, ## args); [tmpPool release]; }} while (0) + +#define EOFLOGClassFnNotImplemented() \ + do { if (GSDebugSet(@"EOFdflt") == YES) { \ + NSAutoreleasePool *tmpPool = [NSAutoreleasePool new]; \ + NSString *fmt = GSDebugFunctionMsg(__PRETTY_FUNCTION__, __FILE__, __LINE__,@"NOT IMPLEMENTED"); \ + NSLog(fmt); [tmpPool release]; }} while (0) + + + +// call in Instance-Methods + +#define EOFLOGObjectFnStart() \ + do { if (GSDebugSet(@"EOFFn") == YES) { \ + NSAutoreleasePool *tmpPool = [NSAutoreleasePool new]; \ + NSString *fmt = GSDebugMethodMsg(self, _cmd, __FILE__, __LINE__,@"FNSTART"); \ + NSLog(fmt); [tmpPool release]; }} while (0) + +#define EOFLOGObjectFnStartOrCond(cond) \ + do { if ((GSDebugSet(@"EOFFn") == YES) || (GSDebugSet(cond) == YES)) { \ + NSAutoreleasePool *tmpPool = [NSAutoreleasePool new]; \ + NSString *fmt = GSDebugMethodMsg(self, _cmd, __FILE__, __LINE__,@"FNSTART"); \ + NSLog(fmt); [tmpPool release]; }} while (0) + +#define EOFLOGObjectFnStartOrCond2(cond1,cond2) \ + do { if ((GSDebugSet(@"EOFFn") == YES) || (GSDebugSet(cond1) == YES) || (GSDebugSet(cond2) == YES)) { \ + NSAutoreleasePool *tmpPool = [NSAutoreleasePool new]; \ + NSString *fmt = GSDebugMethodMsg(self, _cmd, __FILE__, __LINE__,@"FNSTART"); \ + NSLog(fmt); [tmpPool release]; }} while (0) + +#define EOFLOGObjectFnStop() \ + do { if (GSDebugSet(@"EOFFn") == YES) { \ + NSAutoreleasePool *tmpPool = [NSAutoreleasePool new]; \ + NSString *fmt = GSDebugMethodMsg(self, _cmd, __FILE__, __LINE__,@"FNSTOP"); \ + NSLog(fmt); [tmpPool release]; }} while (0) + +#define EOFLOGObjectFnStopOrCond(cond) \ + do { if ((GSDebugSet(@"EOFFn") == YES) || (GSDebugSet(cond) == YES)) { \ + NSAutoreleasePool *tmpPool = [NSAutoreleasePool new]; \ + NSString *fmt = GSDebugMethodMsg(self, _cmd, __FILE__, __LINE__,@"FNSTOP"); \ + NSLog(fmt); [tmpPool release]; }} while (0) + +#define EOFLOGObjectFnStopOrCond2(cond1,cond2) \ + do { if ((GSDebugSet(@"EOFFn") == YES) || (GSDebugSet(cond1) == YES) || (GSDebugSet(cond2) == YES)) { \ + NSAutoreleasePool *tmpPool = [NSAutoreleasePool new]; \ + NSString *fmt = GSDebugMethodMsg(self, _cmd, __FILE__, __LINE__,@"FNSTOP"); \ + NSLog(fmt); [tmpPool release]; }} while (0) + +#define EOFLOGObjectFnStopPlain(fmt) \ + do { if (GSDebugSet(@"EOFFn") == YES) { \ + NSLog(fmt); }} while (0) + +#define EOFLOGObjectFnStopOrCondPlain(cond,fmt) \ + do { if ((GSDebugSet(@"EOFFn") == YES) || (GSDebugSet(cond) == YES)) { \ + NSLog(fmt); }} while (0) + +#define EOFLOGObjectFnStopOrCond2Plain(cond1,cond2,fmt) \ + do { if ((GSDebugSet(@"EOFFn") == YES) || (GSDebugSet(cond1) == YES) || (GSDebugSet(cond2) == YES)) { \ + NSLog(fmt); }} while (0) + +#define EOFLOGObjectLevel(level,format) \ + do { if (GSDebugSet(level) == YES) { \ + NSAutoreleasePool *tmpPool = [NSAutoreleasePool new]; \ + NSString *fmt = GSDebugMethodMsg( \ + self, _cmd, __FILE__, __LINE__, format); \ + NSLog(fmt); [tmpPool release]; }} while (0) + +#define EOFLOGObjectLevelArgs(level, format, args...) \ + do { if (GSDebugSet(level) == YES) { \ + NSAutoreleasePool *tmpPool = [NSAutoreleasePool new]; \ + NSString *fmt = GSDebugMethodMsg( \ + self, _cmd, __FILE__, __LINE__, format); \ + NSLog(fmt, ## args); [tmpPool release]; }} while (0) + +#define EOFLOGObject(format) \ + do { \ + NSAutoreleasePool *tmpPool = [NSAutoreleasePool new]; \ + NSString *fmt = GSDebugMethodMsg( \ + self, _cmd, __FILE__, __LINE__, format); \ + NSLog(fmt); [tmpPool release]; } while (0) + +#define EOFLOGObjectArgs(format, args...) \ + do { \ + NSAutoreleasePool *tmpPool = [NSAutoreleasePool new]; \ + NSString *fmt = GSDebugMethodMsg( \ + self, _cmd, __FILE__, __LINE__, format); \ + NSLog(fmt, ## args); [tmpPool release]; }while (0) + +#define EOFLOGObjectFnNotImplemented() \ + do { if (GSDebugSet(@"EOFdflt") == YES) { \ + NSAutoreleasePool *tmpPool = [NSAutoreleasePool new]; \ + NSString *fmt = GSDebugMethodMsg(self, _cmd, __FILE__, __LINE__,@"NOT IMPLEMENTED"); \ + NSLog(fmt); [tmpPool release]; }} while (0) + + + +// call everywhere + +#define EOFLOGException(format) \ + do { if (GSDebugSet(@"exception") == YES) { \ + NSAutoreleasePool *tmpPool = [NSAutoreleasePool new]; \ + NSString *fmt = GSDebugFunctionMsg(__PRETTY_FUNCTION__, __FILE__, __LINE__,format); \ + NSString *fmt2 = [NSString stringWithFormat:@"*EXCEPTION*: %@",fmt]; \ + NSLog(@"%@",fmt2); [tmpPool release]; }} while (0) + +#define EOFLOGExceptionArgs(format, args...) \ + do { if (GSDebugSet(@"exception") == YES) { \ + NSAutoreleasePool *tmpPool = [NSAutoreleasePool new]; \ + NSString *fmt = GSDebugFunctionMsg(__PRETTY_FUNCTION__, __FILE__, __LINE__,format); \ + NSString *fmt2 = [NSString stringWithFormat:@"*EXCEPTION*: %@",fmt]; \ + NSLog(fmt2, ## args); [tmpPool release]; }} while (0) + +#else // no DEBUG + +#define EOFLOGClassFnStart() {} +#define EOFLOGClassFnStartCond() {} +#define EOFLOGClassFnStartOrCond(cond) {} +#define EOFLOGClassFnStartOrCond2(cond1,cond2) {} +#define EOFLOGClassFnStop() {} +#define EOFLOGClassFnStopCond() {} +#define EOFLOGClassFnStopOrCond(cond) {} +#define EOFLOGClassFnStopOrCond2(cond1,cond2) {} +#define EOFLOGClassLevel(level,format) {} +#define EOFLOGClassLevelArgs(level,format,args...) {} +#define EOFLOGClassFnNotImplemented() {} + +#define EOFLOGObjectFnStart() {} +#define EOFLOGObjectFnStartCond(cond) {} +#define EOFLOGObjectFnStartOrCond(cond) {} +#define EOFLOGObjectFnStartOrCond2(cond1,cond2) {} +#define EOFLOGObjectFnStop() {} +#define EOFLOGObjectFnStopCond(cond) {} +#define EOFLOGObjectFnStopOrCond(cond) {} +#define EOFLOGObjectFnStopOrCond2(cond1,cond2) {} +#define EOFLOGObjectFnStopPlain(fmt) {} +#define EOFLOGObjectFnStopOrCondPlain(cond,fmt) {} +#define EOFLOGObjectFnStopOrCond2Plain(cond1,cond2,fmt) {} +#define EOFLOGObjectLevel(level,format) {} +#define EOFLOGObjectLevelArgs(level,format,args...) {} +#define EOFLOGObject(format) {} +#define EOFLOGObjectArgs(format,args...) {} +#define EOFLOGObjectFnNotImplemented() {} + +#define EOFLOGException(format) {} +#define EOFLOGExceptionArgs(format, args...) {} + +#endif + +#ifndef NSEmitTODO +#define NSEmitTODO(); NSLog(@"DVLP WARNING %s (%d): TODO",(char*)__FILE__,(int)__LINE__); +#endif + +#endif // _EODebug_h__ diff --git a/EOControl/EODebug.m b/EOControl/EODebug.m new file mode 100644 index 0000000..5571948 --- /dev/null +++ b/EOControl/EODebug.m @@ -0,0 +1,402 @@ +/* EODebug.m - debug + + Copyright (C) 1999-2002 Free Software Foundation, Inc. + + Written by: Manuel Guesdon + Date: Jan 1999 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#include +#include +#include +#include + +#define USTART NSAutoreleasePool* arp=[NSAutoreleasePool new]; +#define USTOP DESTROY(arp); + + +@interface NSObject (GSISA) + +-(Class)isa; + +@end + +@implementation NSObject (GSISA) + +-(Class)isa +{ + return self->isa; +} + +@end + +#ifdef DEBUG + +void EOFLogC_(const char *file, int line, const char *string) +{ + int len = 0; + + if ([NSThread isMultiThreaded]) + { + NSThread *t = [NSThread currentThread]; + + fprintf(stderr,"TID="); +#if 0 + if (t && t->_thread_id) + fprintf(stderr,"%p [%ld] (%d) ",(void*)t->_thread_id,(long)t->_thread_id,(int)getpid()); + else +#endif + { + void *tid = (void*)objc_thread_id(); + fprintf(stderr, "%p [%ld] (%d) ", tid, (long)tid, (int)getpid()); + } + } + + fprintf(stderr, "File %s: %d. ", file, line); + fprintf(stderr, string); + + len = strlen(string); + + if (len <= 0 || string[len-1] != '\n') + fprintf(stderr, "\n"); + + fflush(stderr); +} + +#endif + +#ifdef DEBUG + +NSString *objectDescription(id object) +{ + NSString *description = nil; + + if ([object respondsToSelector: @selector(description)]) + { + NS_DURING + description = [object description]; + NS_HANDLER + NS_ENDHANDLER; + } + + return description; +} + +NSString *IVarInString(const char* _type, void* _value) +{ + if (_type && _value) + { + switch (*_type) + { + case _C_ID: + { + id *pvalue = (id*)_value; + return [NSString stringWithFormat: + @"object:%ld Class:%s Description:%@", + (long)(*pvalue), + [*pvalue class], + objectDescription(*pvalue)]; + } + break; + case _C_CLASS: + { + Class *pvalue = (Class*)_value; + return [NSString stringWithFormat: @"Class:%s", + class_get_class_name(*pvalue)]; + } + break; + case _C_SEL: + { + SEL *pvalue = (SEL*)_value; + return [NSString stringWithFormat: @"SEL:%s", + sel_get_name(*pvalue)]; + } + break; + case _C_CHR: + { + char *pvalue = (char*)_value; + return [NSString stringWithFormat: @"CHAR:%c", + *pvalue]; + } + break; + case _C_UCHR: + { + unsigned char *pvalue = (unsigned char*)_value; + return [NSString stringWithFormat: @"UCHAR:%d", + (int)*pvalue]; + } + break; + case _C_SHT: + { + short *pvalue = (short*)_value; + return [NSString stringWithFormat: @"SHORT:%d", + (int)*pvalue]; + } + break; + case _C_USHT: + { + unsigned short *pvalue = (unsigned short*)_value; + return [NSString stringWithFormat: @"USHORT:%d", + (int)*pvalue]; + } + break; + case _C_INT: + { + int *pvalue = (int*)_value; + return [NSString stringWithFormat: @"INT:%d", + *pvalue]; + } + break; + case _C_UINT: + { + unsigned int *pvalue = (unsigned int*)_value; + return [NSString stringWithFormat: @"UINT:%u", + *pvalue]; + } + break; + case _C_LNG: + { + long *pvalue = (long*)_value; + return [NSString stringWithFormat: @"LONG:%ld", + *pvalue]; + } + break; + case _C_ULNG: + { + unsigned long *pvalue = (unsigned long*)_value; + return [NSString stringWithFormat: @"ULONG:%lu", + *pvalue]; + } + break; + case _C_FLT: + { + float *pvalue = (float*)_value; + return [NSString stringWithFormat: @"FLOAT:%f", + (double)*pvalue]; + } + break; + case _C_DBL: + { + double *pvalue = (double*)_value; + return [NSString stringWithFormat: @"DOUBLE:%f", + *pvalue]; + } + break; + case _C_VOID: + { + void *pvalue = (void*)_value; + return [NSString stringWithFormat: @"VOID:*%lX", + (unsigned long)pvalue]; + } + break; + case _C_CHARPTR: + { + char *pvalue = (void*)_value; + return [NSString stringWithFormat: @"CHAR*:%s", + pvalue]; + } + break; + case _C_PTR: + { + return [NSString stringWithFormat: @"PTR"]; + } + break; + case _C_STRUCT_B: + { + return [NSString stringWithFormat: @"STRUCT"]; + } + break; + default: + return [NSString stringWithFormat: @"Unknown"]; + } + } + else + return [NSString stringWithString: @"NULL type or NULL pValue"]; +} + +NSString *TypeToNSString(const char* _type) +{ + if (_type) + { + switch (*_type) + { + case _C_ID: + { // '@' + const char *t = _type + 1; + + if (*t == '"') + { + const char *start = t + 1; + + do + { + t++; + } + while ((*t != '"') && (*t != '\0')); + + return [[NSString stringWithCString: start + length: (t - start)] + stringByAppendingString: @" *"]; + } + else + return @"id"; + }; + break; + case _C_CLASS: return @"Class"; + case _C_SEL: return @"SEL"; + case _C_CHR: return @"char"; + case _C_UCHR: return @"unsigned char"; + case _C_SHT: return @"short"; + case _C_USHT: return @"unsigned short"; + case _C_INT: return @"int"; + case _C_UINT: return @"unsigned int"; + case _C_LNG: return @"long"; + case _C_ULNG: return @"unsigned long"; +// case _C_LNG_LNG: return @"long long"; +// case _C_ULNG_LNG: return @"unsigned long long"; + case _C_FLT: return @"float"; + case _C_DBL: return @"double"; + case _C_VOID: return @"void"; + case _C_CHARPTR: return @"char *"; + case _C_PTR: + return [NSString stringWithFormat: @"%@ *", + TypeToNSString(_type + 1)]; + break; + case _C_STRUCT_B: + { + NSString *structName = nil; + const char *t = _type + 1; + + if (*t == '?') + structName = @"?"; + else + { + const char *beg = t; + + while ((*t != '=') && (*t != '\0') && (*t != _C_STRUCT_E)) + t++; + structName = [NSString stringWithCString:beg length:(t - beg)]; + } + + return [NSString stringWithFormat: @"struct %@ {...}", structName]; + } + + default: + return [NSString stringWithFormat: @"%s", _type]; + } + } + else + return [NSString stringWithString: @"NULL type"]; +} + +void DumpIVar(id object, struct objc_ivar *ivar, int deep) +{ + if (ivar && object && deep >= 0) + { + void *pValue = ((void*)object) + ivar->ivar_offset; + NSString *pType = TypeToNSString(ivar->ivar_type); + NSString *pIVar = IVarInString(ivar->ivar_type,pValue); + + NSDebugFLog(@"IVar %s type:%@ value:%@\n", + ivar->ivar_name, + pType, + pIVar); + + if (deep > 0 && ivar->ivar_type && *ivar->ivar_type == _C_ID && pValue) + { + EOFLogDumpObject_(NULL, 0, *((id*)pValue), deep); + } + } +} + +//Dump object +void EOFLogDumpObject_(const char *file, int line, id object, int deep) +{ + USTART + + if (object && deep > 0) + { + struct objc_ivar_list *ivars = NULL; + Class class = [object class]; + + if (class) + { + NSDebugFLog(@"--%s %d [%d] Dumping object %p of Class %s Description:%@\n", + (file && isalpha(*file) && line >= 0 + && line<=20000) ? file :"", + line, + deep, + (void*)object, + class->name, + objectDescription(object)); + while (class) + { + ivars = class->ivars; + class = class->super_class; + + if (ivars) + { + int i; + + for (i = 0; i < ivars->ivar_count; i++) + { + DumpIVar(object,&ivars->ivar_list[i],deep-1); + } + } + } + } + } + + USTOP +} + +void EOFLogAssertGood_(const char *file, int line, NSObject *object) +{ + if (object) + { + if ([object isa] == ((Class)0xdeadface)) + { + NSLog(@"DEAD FACE: object %p isa=%p in %s at %d\n", + (void*)object, + (void*)[object isa], + file, + line); + NSCParameterAssert([object isa] == (Class)0xdeadface); + } + } + else + { + NSLog(@"NULL: object %p in %s at %d\n", + (void*)object, + file, + line); + NSCParameterAssert(object); + } +} + +#endif diff --git a/EOControl/EODetailDataSource.h b/EOControl/EODetailDataSource.h new file mode 100644 index 0000000..3996293 --- /dev/null +++ b/EOControl/EODetailDataSource.h @@ -0,0 +1,62 @@ +/* + EODetailDataSource.m + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: July 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#import + + +@interface EODetailDataSource : EODataSource +{ + EODataSource *_masterDataSource; + id _masterObject; + NSString *_detailKey; + NSString *_masterClassDescriptionName; +} + ++ (EODetailDataSource *)detailDataSourceWithMasterDataSource: (EODataSource *)master + detailKey: (NSString *)detailKey; + +- initWithMasterClassDescription: (EOClassDescription *)masterClassDescription + detailKey: (NSString *)detailKey; + +- initWithMasterDataSource: (EODataSource *)master + detailKey: (NSString *)detailKey; + +- (id) initWithKeyValueUnarchiver: (EOKeyValueUnarchiver *)unarchiver; + +- (EODataSource *)masterDataSource; + +- (EOClassDescription *)masterClassDescription; +- (void)setMasterClassDescription: (EOClassDescription *)classDescription; +- (EOClassDescription *)classDescriptionForObjects; + +- (void)qualifyWithRelationshipKey: (NSString *)key + ofObject: masterObject; +- (NSString *)detailKey; +- (id)masterObject; + +- (EOEditingContext *)editingContext; + +@end diff --git a/EOControl/EODetailDataSource.m b/EOControl/EODetailDataSource.m new file mode 100644 index 0000000..d3bcac8 --- /dev/null +++ b/EOControl/EODetailDataSource.m @@ -0,0 +1,271 @@ +/** + EODetailDataSource.m EODetailDataSource Class + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: July 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import +#import +#import +#import +#import +#import +#import + + +@implementation EODetailDataSource + ++ (EODetailDataSource *)detailDataSourceWithMasterDataSource: (EODataSource *)master + detailKey: (NSString *)detailKey +{ + return [[[self alloc] initWithMasterDataSource: master + detailKey: detailKey] autorelease]; +} + +- initWithMasterClassDescription: (EOClassDescription *)masterClassDescription + detailKey: (NSString *)detailKey +{ + if ((self = [super init])) + { + [self setMasterClassDescription: masterClassDescription]; + [self qualifyWithRelationshipKey: detailKey + ofObject: nil]; + } + + return self; +} + +- initWithMasterDataSource: (EODataSource *)master + detailKey: (NSString *)detailKey +{ + ASSIGN(_masterDataSource, master); + + return [self initWithMasterClassDescription: nil + detailKey: detailKey]; +} + +- (id)initWithKeyValueUnarchiver: (EOKeyValueUnarchiver *)unarchiver +{ + //OK + EOFLOGObjectFnStart(); + + if ((self = [self init])) + { + NSString* detailKey=nil; + NSString* masterClassDescriptionName=nil; + EOClassDescription* masterClassDescription=nil; + + EOFLOGObjectLevelArgs(@"EODataSource",@"EODetailDataSource %p",self); + + detailKey = [unarchiver decodeObjectForKey: @"detailKey"]; + masterClassDescriptionName = [unarchiver decodeObjectForKey: + @"masterClassDescription"]; + masterClassDescription = [EOClassDescription + classDescriptionForEntityName: + masterClassDescriptionName]; + + [self setMasterClassDescription: masterClassDescription]; + [self qualifyWithRelationshipKey: detailKey + ofObject: nil]; + + EOFLOGObjectLevelArgs(@"EODataSource", @"EODetailDataSource %p : %@", + self, self); + } + + EOFLOGObjectFnStop(); + + return self; +} + +- (void)dealloc +{ + DESTROY(_masterDataSource); + DESTROY(_masterObject); + DESTROY(_detailKey); + DESTROY(_masterClassDescriptionName); + + [super dealloc]; +} + +- (EODataSource *)masterDataSource +{ + return _masterDataSource; +} + +- (EOClassDescription *)masterClassDescription +{ + return [EOClassDescription classDescriptionForEntityName: + _masterClassDescriptionName]; +} + +- (void)setMasterClassDescription: (EOClassDescription *)classDescription +{ + EOFLOGObjectFnStart(); + + ASSIGN(_masterClassDescriptionName, [classDescription entityName]); + + EOFLOGObjectFnStop(); +} + +- (EOClassDescription *)classDescriptionForObjects +{ + EOClassDescription *cd; + EOClassDescription *masterCD; + NSString *detailKey; + + detailKey = [self detailKey]; + NSAssert(detailKey, @"No detailKey"); + + masterCD = [self masterClassDescription]; + NSAssert(masterCD, @"No masterClassDescription"); + + cd = [masterCD classDescriptionForDestinationKey: detailKey]; + + return cd; +} + +- (void)qualifyWithRelationshipKey: (NSString *)key + ofObject: masterObject +{ + EOFLOGObjectFnStart(); + + ASSIGN(_detailKey, key); + ASSIGN(_masterObject, masterObject); + + EOFLOGObjectFnStop(); +} + +- (NSString *)detailKey +{ + return _detailKey; +} + +- (id)masterObject +{ + return _masterObject; +} + +- (EOEditingContext *)editingContext +{ + return [_masterObject editingContext]; +} + +- (NSArray *)fetchObjects +{ + id value=nil; + + EOFLOGObjectFnStart(); + + if(!_masterObject) + value = [NSArray array]; + else if(!_detailKey) + value = [NSArray arrayWithObject: _masterObject]; + else + { + value = [_masterObject valueForKey: _detailKey]; + + if (value) + { + if (![value isKindOfClass: [NSArray class]]) + value = [NSArray arrayWithObject: value]; + } + else + value = [NSArray array]; + } + + EOFLOGObjectFnStop(); + + return value; +} + +- (void)insertObject: (id)object +{ + EOFLOGObjectFnStart(); + + if (!_masterObject) + [NSException raise: NSInternalInconsistencyException + format: @"%@ -- %@ 0x%x: no masterObject", + NSStringFromSelector(_cmd), NSStringFromClass([self class]), + self]; + + if (!_detailKey) + [NSException raise: NSInternalInconsistencyException + format: @"%@ -- %@ 0x%x: no detailKey", + NSStringFromSelector(_cmd), NSStringFromClass([self class]), + self]; + + [_masterObject addObject: object + toBothSidesOfRelationshipWithKey: _detailKey]; + + EOFLOGObjectFnStop(); +} + +- (void)deleteObject: (id)object +{ + if (!_masterObject) + [NSException raise: NSInternalInconsistencyException + format: @"%@ -- %@ 0x%x: no masterObject", + NSStringFromSelector(_cmd), NSStringFromClass([self class]), + self]; + + if (!_detailKey) + [NSException raise: NSInternalInconsistencyException + format: @"%@ -- %@ 0x%x: no detailKey", + NSStringFromSelector(_cmd), NSStringFromClass([self class]), + self]; + + [_masterObject removeObject: object fromPropertyWithKey: _detailKey]; +} + +- (id)initWithCoder: (NSCoder *)coder +{ + if ((self = [super init])) + { + ASSIGN(_masterDataSource, [coder decodeObject]); + ASSIGN(_masterObject, [coder decodeObject]); + ASSIGN(_detailKey, [coder decodeObject]); + ASSIGN(_masterClassDescriptionName, [coder decodeObject]); + } + + return self; +} + +- (void)encodeWithCoder: (NSCoder *)coder +{ + [coder encodeObject: _masterDataSource]; + [coder encodeObject: _masterObject]; + [coder encodeObject: _detailKey]; + [coder encodeObject: _masterClassDescriptionName]; +} + +@end diff --git a/EOControl/EOEditingContext.h b/EOControl/EOEditingContext.h new file mode 100644 index 0000000..4a8d412 --- /dev/null +++ b/EOControl/EOEditingContext.h @@ -0,0 +1,359 @@ +/* + EOEditingContext.h + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Date: June 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOEditingContext_h__ +#define __EOEditingContext_h__ + +#import +#import +#import + +@interface EOEditingContext : EOObjectStore +{ + EOObjectStore *_objectStore; + NSUndoManager *_undoManager; + NSHashTable *_unprocessedChanges; + NSHashTable *_unprocessedDeletes; + NSHashTable *_unprocessedInserts; + NSHashTable *_insertedObjects; + NSHashTable *_deletedObjects; + NSHashTable *_changedObjects; + + NSMapTable *_objectsById; + NSMapTable *_objectsByGID; + NSMutableDictionary *_snapshotsByGID; + NSMutableDictionary *_eventSnapshotsByGID; + + id _delegate; + NSMutableArray *_editors; + id _messageHandler; + unsigned short _undoTransactionID; + struct { + unsigned registeredForCallback:1; + unsigned propagatesDeletesAtEndOfEvent:1; + unsigned ignoreChangeNotification:1; + unsigned exhaustiveValidation:1;// unsigned stopsValidation:1; + unsigned autoLocking:1; + unsigned processingChanges:1;// unsigned savingChanges:1; + unsigned skipInvalidateOnDealloc:1; + unsigned useCommittedSnapshot:1; + unsigned registeredUndoTransactionID:1; + unsigned retainsAllRegisteredObjects:1; + unsigned lockUsingParent:1; + unsigned unused:5; + } _flags; + struct { + unsigned willRunLoginPanel:1; + unsigned shouldFetchObjects:1; + unsigned shouldInvalidateObject:1; + unsigned shouldMergeChanges:1; + unsigned shouldPresentException:1; + unsigned shouldUndoUserActions:1; + unsigned shouldValidateChanges:1; + unsigned willSaveChanges:1; + } _delegateRespondsTo; + + NSRecursiveLock*_lock; + int _lockCount; + id _notificationQueue; + NSAutoreleasePool * _lockPool; +} + ++ (void)setInstancesRetainRegisteredObjects: (BOOL)flag; ++ (BOOL)instancesRetainRegisteredObjects; + +- initWithParentObjectStore:(EOObjectStore *)parentObjectStore; + +- init; + +- (NSArray *)objectsWithFetchSpecification: (EOFetchSpecification *)fetchSpecification; + +- (void)insertObject: (id)object; +- (void)insertObject: object + withGlobalID: (EOGlobalID *)gid; +- (void)_insertObject: (id)object + withGlobalID: (EOGlobalID *)gid; + +- (void)deleteObject: (id)object; + +- (void)lockObject: (id)object; + +- (BOOL)hasChanges; + +- (void)saveChanges; + +- (void)revert; + +- (id)objectForGlobalID: (EOGlobalID *)globalID; +- (EOGlobalID *)globalIDForObject: object; + +- (void)setDelegate: (id)delegate; +- (id)delegate; + +- (EOObjectStore *)parentObjectStore; + +- (EOObjectStore *)rootObjectStore; + + +- (void)setUndoManager: (NSUndoManager *)undoManager; +- (NSUndoManager *)undoManager; + +- (void) _observeUndoManagerNotifications; + +- (void)objectWillChange: (id)object; + +- (void)recordObject: (id)object + globalID: (EOGlobalID *)globalID; + +- (void)forgetObject: (id)object; + +- (void) registerUndoForModifiedObject: (id)object; + +- (NSArray *)registeredObjects; + +- (NSArray *)updatedObjects; +- (NSArray *)insertedObjects; +- (NSArray *)deletedObjects; + +- (void) _processDeletedObjects; +- (void) _processOwnedObjectsUsingChangeTable: (NSHashTable*)changeTable + deleteTable: (NSHashTable*)deleteTable; +- (void) propagatesDeletesUsingTable: (NSHashTable*)deleteTable; +- (void) validateDeletesUsingTable: (NSHashTable*)deleteTable; +- (BOOL) validateTable: (NSHashTable*)table + withSelector: (SEL)sel + exceptionArray: (NSMutableArray**)exceptionArray + continueAfterFailure: (BOOL)continueAfterFailure; + + +- (void)processRecentChanges; +- (void) _registerClearStateWithUndoManager; + +- (BOOL)propagatesDeletesAtEndOfEvent; +- (void)setPropagatesDeletesAtEndOfEvent: (BOOL)propagatesDeletesAtEndOfEvent; + +- (BOOL)stopsValidationAfterFirstError; +- (void)setStopsValidationAfterFirstError: (BOOL)yn; + +- (BOOL)locksObjectsBeforeFirstModification; +- (void)setLocksObjectsBeforeFirstModification: (BOOL)yn; + +/** Returns a dictionary containing a snapshot of object +that reflects its committed values (last values putted in +the database; i.e. values before changes were made on the +object). +It is updated after commiting new values. +**/ +- (NSDictionary *)committedSnapshotForObject: (id)object; + +/** Returns a dictionary containing a snapshot of object +with its state as it was at the beginning of the current +event loop. +After the end of the current event, upon invocation of +processRecentChanges, the snapshot is updated to hold the +modified state of the object.**/ +- (NSDictionary *)currentEventSnapshotForObject: (id)object; + +- (NSDictionary *)uncommittedChangesForObject: (id)object; + +- (void)refaultObjects; + +- (void)setInvalidatesObjectsWhenFreed: (BOOL)yn; +- (BOOL)invalidatesObjectsWhenFreed; + +- (void)addEditor: (id)editor; +- (void)removeEditor: (id)editor; +- (NSArray *)editors; + +- (void)setMessageHandler: (id)handler; +- (id)messageHandler; + + +- (id)faultForGlobalID: (EOGlobalID *)globalID + editingContext: (EOEditingContext *)context; + +- (id)faultForRawRow: (NSDictionary *)row + entityNamed: (NSString *)entityName + editingContext: (EOEditingContext *)context; + +- (id)faultForRawRow: (NSDictionary *)row + entityNamed: (NSString *)entityName; + +- (NSArray *)arrayFaultWithSourceGlobalID: (EOGlobalID *)globalID + relationshipName: (NSString *)name + editingContext: (EOEditingContext *)context; + +- (void)initializeObject: (id)object + withGlobalID: (EOGlobalID *)globalID + editingContext: (EOEditingContext *)context; + +- (NSArray *)objectsForSourceGlobalID: (EOGlobalID *)globalID + relationshipName: (NSString *)name + editingContext: (EOEditingContext *)context; + +- (void)refaultObject: object + withGlobalID: (EOGlobalID *)globalID + editingContext: (EOEditingContext *)context; + +- (void)saveChangesInEditingContext: (EOEditingContext *)context; + +- (NSArray *)objectsWithFetchSpecification: (EOFetchSpecification *)fetchSpecification + editingContext: (EOEditingContext *)context; + +- (void)lockObjectWithGlobalID: (EOGlobalID *)gid + editingContext: (EOEditingContext *)context; + +- (BOOL)isObjectLockedWithGlobalID: (EOGlobalID *)gid + editingContext: (EOEditingContext *)context; + +- (void) clearOriginalSnapshotForObject: (id)object; + +@end + +// used with NSRunLoop's performSelector:target:argument:order:modes: +enum { + EOEditingContextFlushChangesRunLoopOrdering = 300000 +}; + +extern NSString *EOObjectsChangedInEditingContextNotification; + +extern NSString *EOEditingContextDidSaveChangesNotification; + + +@interface NSObject (EOEditingContext) + +- (EOEditingContext *)editingContext; + +@end + +// +// Delegation methods +// +@interface NSObject (EOEditingContextDelegation) + +- (BOOL)editingContext: (EOEditingContext *)editingContext +shouldPresentException: (NSException *)exception; + +- (BOOL)editingContextShouldValidateChanges: (EOEditingContext *)editingContext; + +- (void)editingContextWillSaveChanges: (EOEditingContext *)editingContext; + +- (BOOL)editingContext: (EOEditingContext *)editingContext +shouldInvalidateObject: (id)object + globalID: (EOGlobalID *)gid; + +- (BOOL)editingContextShouldUndoUserActionsAfterFailure: (EOEditingContext *)context; + +- (NSArray *)editingContext: (EOEditingContext *)editingContext +shouldFetchObjectsDescribedByFetchSpecification: (EOFetchSpecification *)fetchSpecification; + +- (BOOL) editingContext: (EOEditingContext *)editingContext +shouldMergeChangedObject: (id)object; + +- (void)didMergeChangedObjectsInEditingContext: (EOEditingContext *)editingContext; + +@end + +// +// EOEditors informal protocol +// +@interface NSObject (EOEditors) + +- (BOOL)editorHasChangesForEditingContext: (EOEditingContext *)editingContext; + +- (void)editingContextWillSaveChanges: (EOEditingContext *)editingContext; + +@end + +// +// EOMessageHandler informal protocol +// +@interface NSObject (EOMessageHandlers) + +- (void)editingContext: (EOEditingContext *)editingContext + presentErrorMessage: (NSString *)message; + +- (BOOL)editingContext: (EOEditingContext *)editingContext +shouldContinueFetchingWithCurrentObjectCount: (unsigned)count + originalLimit: (unsigned)limit + objectStore: (EOObjectStore *)objectStore; + +@end + + +@interface EOEditingContext (EORendezvous) + ++ (void)setSubstitutionEditingContext: (EOEditingContext *)ec; ++ (EOEditingContext *)substitutionEditingContext; + ++ (void)setDefaultParentObjectStore: (EOObjectStore *)store; ++ (EOObjectStore *)defaultParentObjectStore; + +@end + +@interface EOEditingContext (EOStateArchiving) + ++ (void)setUsesContextRelativeEncoding: (BOOL)yn; ++ (BOOL)usesContextRelativeEncoding; ++ (void)encodeObject: (id)object withCoder: (NSCoder *)coder; ++ (id)initObject: (id)object withCoder: (NSCoder *)coder; + + +@end + +@interface EOEditingContext (EOTargetAction) + +- (void)saveChanges: (id)sender; +- (void)refault: (id)sender; +- (void)revert: (id)sender; +- (void)refetch: (id)sender; + +- (void)undo: (id)sender; +- (void)redo: (id)sender; + +//Private +-(NSString*)objectsDescription; +-(NSString*)unprocessedDescription; + +@end + +@interface EOEditingContext(EOMultiThreaded) + ++ (void)setEOFMultiThreadedEnabled: (BOOL)flag; +- (void)lock; +- (void)unlock; +- (BOOL) tryLock; + +@end + +// Informations +@interface EOEditingContext(EOEditingContextInfo) + +- (NSDictionary*)unprocessedInfo; +- (NSDictionary*)pendingInfo; + +@end + +#endif diff --git a/EOControl/EOEditingContext.m b/EOControl/EOEditingContext.m new file mode 100644 index 0000000..5a9423d --- /dev/null +++ b/EOControl/EOEditingContext.m @@ -0,0 +1,3105 @@ +/** + EOEditingContext.m EOEditingContext Class + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Date: June 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +//TODO EOMultiReaderLocks +#import +#import + +#import +#import + +#import +#import +#import +#import +#import +#import +#import +#import + +#import +#import + + +@implementation EOEditingContext + + +static EOObjectStore *defaultParentStore = nil; + +//Notifications +NSString *EOObjectsChangedInEditingContextNotification = @"EOObjectsChangedInEditingContextNotification"; +NSString *EOEditingContextDidSaveChangesNotification = @"EOEditingContextDidSaveChangesNotification"; + + ++ (void)initialize +{ + if (self == [EOEditingContext class] && !defaultParentStore) + defaultParentStore = [EOObjectStoreCoordinator defaultCoordinator]; +} + ++ (void)setInstancesRetainRegisteredObjects: (BOOL)flag +{ + [self notImplemented: _cmd]; +} + ++ (BOOL)instancesRetainRegisteredObjects +{ + [self notImplemented: _cmd]; + return NO; +} + +- (void) _eoNowMultiThreaded: (NSNotification *)notification +{ + //TODO +} + +- (id) initWithParentObjectStore: (EOObjectStore *)parentObjectStore +{ + //OK + if ((self = [super init])) + { + _flags.propagatesDeletesAtEndOfEvent = YES; //Default behavior + ASSIGN(_objectStore, [EOEditingContext defaultParentObjectStore]); //parentObjectStore instead of defaultParentObjectStore ? + + _unprocessedChanges = NSCreateHashTable(NSObjectHashCallBacks, 32); + _unprocessedDeletes = NSCreateHashTable(NSObjectHashCallBacks, 32); + _unprocessedInserts = NSCreateHashTable(NSObjectHashCallBacks, 32); + _insertedObjects = NSCreateHashTable(NSObjectHashCallBacks, 32); + _deletedObjects = NSCreateHashTable(NSObjectHashCallBacks, 32); + _changedObjects = NSCreateHashTable(NSObjectHashCallBacks, 32); + + _objectsById = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,//NSObjectMapKeyCallBacks, retained by _objectsByGID + NSObjectMapValueCallBacks, + 32); + _objectsByGID = NSCreateMapTable(NSObjectMapKeyCallBacks, + NSObjectMapValueCallBacks, + 32); + + _snapshotsByGID = [[NSMutableDictionary alloc] initWithCapacity:16]; + _eventSnapshotsByGID = [[NSMutableDictionary alloc] initWithCapacity:16]; + + _editors = [NSMutableArray new]; + + _lock = [NSRecursiveLock new]; + +//TODO-NOW _undoManager = [EOUndoManager new]; + [_undoManager beginUndoGrouping]; //?? + + [self _observeUndoManagerNotifications]; + +/* + [self setStopsValidationAfterFirstError:YES]; + [self setPropagatesDeletesAtEndOfEvent:YES]; +*/ + + [[NSNotificationCenter defaultCenter] + addObserver: self + selector: @selector(_objectsChangedInStore:) + name: EOObjectsChangedInStoreNotification + object: _objectStore]; + + [[NSNotificationCenter defaultCenter] + addObserver: self + selector: @selector(_invalidatedAllObjectsInStore:) + name: EOInvalidatedAllObjectsInStoreNotification + object: _objectStore]; + + [[NSNotificationCenter defaultCenter] + addObserver: self + selector: @selector(_globalIDChanged:) + name: EOGlobalIDChangedNotification + object: nil]; + + [[NSNotificationCenter defaultCenter] + addObserver: self + selector: @selector(_eoNowMultiThreaded:) + name: NSWillBecomeMultiThreadedNotification + object: nil]; +/* + [self setStopsValidationAfterFirstError:NO]; + + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(_objectsChangedInSubStore:) + name:EOObjectsChangedInStoreNotification + object:nil]; +*/ + } + + return self; +} + +- (id) init +{ + return [self initWithParentObjectStore: + [EOEditingContext defaultParentObjectStore]]; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + DESTROY(_objectStore); + DESTROY(_undoManager); + + NSFreeHashTable(_unprocessedChanges); + NSFreeHashTable(_unprocessedDeletes); + NSFreeHashTable(_unprocessedInserts); + NSFreeHashTable(_insertedObjects); + NSFreeHashTable(_deletedObjects); + NSFreeHashTable(_changedObjects); + + NSFreeMapTable(_objectsById); + NSFreeMapTable(_objectsByGID); + + DESTROY(_snapshotsByGID); + DESTROY(_eventSnapshotsByGID); + + DESTROY(_editors); + DESTROY(_lock); + + [super dealloc]; +} + +- (id) parentPath +{ + NSEmitTODO(); + return [self notImplemented: _cmd]; //TODO +} + +-(void)_observeUndoManagerNotifications +{ + //OK + [[NSNotificationCenter defaultCenter] + addObserver: self + selector: @selector(_undoManagerCheckpoint:) + name: NSUndoManagerCheckpointNotification + object: _undoManager]; +} + +- (void) _processObjectStoreChanges: (NSNotification *)notification +{ + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@", + [self unprocessedDescription]); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@", + [self objectsDescription]); + + [self notImplemented: _cmd]; //TODO +} + +//"Receive EOObjectsChangedInStoreNotification notification" +//oldname:_handleObjectsChangedInStoreNotification: +- (void)_objectsChangedInStore: (NSNotification *)notification +{ + NSEnumerator *arrayEnum; + EOGlobalID *gid; + NSArray *array = nil; + + NSEmitTODO(); + // userInfo = {deleted = (); inserted = (); updated = ([GID: CustomerCredit, (1)]); }} + + if ([notification object] != self) + { + // Notification is posted from EODatabase + array = [[notification userInfo] objectForKey: EOInsertedKey]; + + if (array) + { + } + + array = [[notification userInfo] objectForKey: EODeletedKey]; + if (array) + { + } + + array = [[notification userInfo] objectForKey: EOUpdatedKey]; + if (array) + { + if (_flags.processingChanges == NO) + { + arrayEnum = [array objectEnumerator]; + + while ((gid = [arrayEnum nextObject])) + { + [self refaultObject: [self objectForGlobalID:gid] + withGlobalID: gid + editingContext: self]; + + // TODO: verify modified objects + } + } + } + + array = [[notification userInfo] objectForKey: EOInvalidatedKey]; + if (array) + { + // these none-EOTemporary-GID EOObjects are retransformed into EOFaults + // all snapshots accesses to their gid's are invalid and must remove + + arrayEnum = [array objectEnumerator]; + while ((gid = [arrayEnum nextObject])) + { + if ([gid isTemporary] == NO) + { + [_snapshotsByGID removeObjectForKey: gid]; + [_eventSnapshotsByGID removeObjectForKey: gid]; + } + } + } + } +} + +//"Receive EOGlobalIDChangedNotification notification" +- (void)_globalIDChanged: (NSNotification *)notification +{ + NSDictionary *snapshot = nil; + NSDictionary *userInfo; + NSEnumerator *enumerator; + EOGlobalID *tempGID; + EOGlobalID *gid = nil; + id object = nil; + + EOFLOGObjectFnStart(); + + userInfo = [notification userInfo]; + enumerator = [userInfo keyEnumerator]; + + while ((tempGID = [enumerator nextObject])) + { + EOFLOGObjectLevelArgs(@"EOEditingContext", @"tempGID=%@", tempGID); + + gid = [userInfo objectForKey: tempGID]; + EOFLOGObjectLevelArgs(@"EOEditingContext", @"gid=%@", gid); + + if (_objectsByGID) + { + object = NSMapGet(_objectsByGID, tempGID); + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"object=%@", object); + + RETAIN(object); + NSAssert(_objectsById, @"no _objectsById"); + + if (object) + { + NSMapInsert(_objectsById, object, gid); + NSMapRemove(_objectsByGID, tempGID); + NSMapInsert(_objectsByGID, gid, object); + AUTORELEASE(object); + } + } + + if (!object) + { + // object is from other editingcontext + EOFLOGObjectLevelArgs(@"EOEditingContextValues", + @"nothing done , object with gid '%@' is from other ed", + tempGID); + } + + //if (object) + snapshot = [_snapshotsByGID objectForKey: tempGID]; + EOFLOGObjectLevelArgs(@"EOEditingContext", + @"_snapshotsByGID snapshot=%@", snapshot); + + if (snapshot) + { + RETAIN(snapshot); + + [_snapshotsByGID removeObjectForKey: tempGID]; + EOFLOGObjectLevelArgs(@"EOEditingContext", @"After Remove"); + + [_snapshotsByGID setObject: snapshot + forKey: gid]; + EOFLOGObjectLevelArgs(@"EOEditingContext", @"After SetObject"); + + AUTORELEASE(snapshot); + } + else + { + // set snapshot with last committed values + //EOFLOGObjectLevelArgs(@"EOEditingContextValues", @"adding new object = %@", [self objectForGlobalID:gid]); + //EOFLOGObjectLevelArgs(@"EOEditingContextValues", @"object class = %@", NSStringFromClass([object class])); + //EOFLOGObjectLevelArgs(@"EOEditingContextValues", @"with snapshot = %@", [[self objectForGlobalID:gid] snapshot]); + + // ?? [_snapshots setObject:[[self objectForGlobalID:gid] snapshot] forKey:gid]; + } + + snapshot = [_eventSnapshotsByGID objectForKey: tempGID]; + EOFLOGObjectLevelArgs(@"EOEditingContext", + @"_eventSnapshotsByGID snapshot=%@", snapshot); + + if (snapshot) + { + RETAIN(snapshot); + [_eventSnapshotsByGID removeObjectForKey: tempGID]; + [_eventSnapshotsByGID setObject: snapshot + forKey: gid]; + + AUTORELEASE(snapshot); + } + } + + EOFLOGObjectFnStop(); +} + +- (void) _processNotificationQueue +{ + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO +} + +- (void) _sendOrEnqueueNotification: (id)param0 + selector: (SEL)param1 +{ + [self notImplemented: _cmd]; //TODO +} + +//"Invalidate All Objects" +- (void) invalidateAllObjects +{ + NSEmitTODO(); + + [super invalidateAllObjects]; //?? + [self notImplemented: _cmd]; //TODO-NOW +} + +//"Receive ???? notification" +- (void) _invalidatedAllObjectsInStore: (NSNotification*)notification +{ + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO +} + +- (void) _forgetObjectWithGlobalID:(EOGlobalID*)gid +{ + NSEmitTODO(); + [self notImplemented:_cmd]; //TODO +} + +- (void) _invalidateObject: (id)object + withGlobalID: (EOGlobalID*)gid +{ + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO +} + +- (void) _invalidateObjectWithGlobalID: (EOGlobalID*)gid +{ + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO +} + +- (void) invalidateObjectsWithGlobalIDs: (NSArray*)gids +{ + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO +} + +- (void) _resetAllChanges: (NSNotification*)notification //?? +{ + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO +} + +- (void) _resetAllChanges +{ + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO +} + +- (void) _enqueueEndOfEventNotification +{ + [_undoManager groupsByEvent]; + [_undoManager registerUndoWithTarget: self + selector: @selector(noop:) + object: nil]; + + _flags.registeredForCallback = YES; +} + +- (NSArray *)objectsWithFetchSpecification: (EOFetchSpecification *)fetch +{ + NSArray *objects; + + EOFLOGObjectFnStart(); + + objects = [self objectsWithFetchSpecification: fetch + editingContext: self]; + + EOFLOGObjectFnStop(); + + return objects; +} + +- (void)insertObject: (id)object +{ + EOGlobalID *gid; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"object=%@", object); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@", + [self unprocessedDescription]); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@", + [self objectsDescription]); + + gid = [self globalIDForObject: object]; + EOFLOGObjectLevelArgs(@"EOEditingContext", @"gid=%@", gid); + + //GSWDisplayGroup -insertAtIndex+EODataSource createObject call insert ! So object is inserted twice + + if (_insertedObjects && NSHashGet(_insertedObjects, object)) + { +// NSLog(@"Already inserted object [_insertedObjects] %p=%@",object,object); +// EOFLOGObjectLevelArgs(@"EOEditingContext",@"Already inserted object [_insertedObjects] %p=%@",object,object); + } + else if (_unprocessedInserts && NSHashGet(_unprocessedInserts, object)) + { +// NSLog(@"Already inserted object [_unprocessedInserts] %p=%@",object,object); +// EOFLOGObjectLevelArgs(@"EOEditingContext",@"Already inserted object [_unprocessedInserts] %p=%@",object,object); + } + else + { + if (!gid) + { + gid = [EOTemporaryGlobalID temporaryGlobalID]; + EOFLOGObjectLevelArgs(@"EOEditingContext", @"gid=%@", gid); + } + + EOFLOGObjectLevelArgs(@"EOEditingContext", + @"InsertObjectWithGlobalID object: %p=%@", + object, object); + + [self insertObject: object + withGlobalID: gid]; + } + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@", + [self unprocessedDescription]); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@", + [self objectsDescription]); + + EOFLOGObjectFnStop(); +} + +- (void)insertObject: (id)object + withGlobalID: (EOGlobalID *)gid +{ + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"object=%@", object); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"gid=%@", gid); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@", + [self unprocessedDescription]); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@", + [self objectsDescription]); + + //GSWDisplayGroup -insertAtIndex+EODataSource createObject call insert ! So object is inserted twice + + if (_insertedObjects && NSHashGet(_insertedObjects, object)) + { +// NSLog(@"Already inserted object [_insertedObjects] %p=%@",object,object); +// EOFLOGObjectLevelArgs(@"EOEditingContext", @"Already inserted object [_insertedObjects] %p=%@", object, object); + } + else if (_unprocessedInserts && NSHashGet(_unprocessedInserts, object)) + { +// NSLog(@"Already inserted object [_unprocessedInserts] %p=%@",object,object); +// EOFLOGObjectLevelArgs(@"EOEditingContext", @"Already inserted object [_unprocessedInserts] %p=%@", object, object); + } + + [self _insertObject: object + withGlobalID: gid]; + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Awake object: %p=%@", + object, object); + + [object awakeFromInsertionInEditingContext: self]; + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@", + [self unprocessedDescription]); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@", + [self objectsDescription]); + + EOFLOGObjectFnStop(); +} + +- (void)_insertObject: (id)object + withGlobalID: (EOGlobalID *)gid +{ + EOGlobalID *gidBis = nil; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Object %p=%@", object, object); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@", + [self unprocessedDescription]); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@", + [self objectsDescription]); + + NSAssert(object, @"No Object"); + + //GSWDisplayGroup -insertAtIndex+EODataSource createObject call insert ! So object is inserted twice + + if (_insertedObjects && NSHashGet(_insertedObjects, object)) + { +// NSLog(@"Already inserted object [_insertedObjects] %p=%@",object,object); +// EOFLOGObjectLevelArgs(@"EOEditingContext", @"Already inserted object [_insertedObjects] %p=%@", object, object); + } + else if (_unprocessedInserts && NSHashGet(_unprocessedInserts, object)) + { +// NSLog(@"Already inserted object [_unprocessedInserts] %p=%@",object,object); +// EOFLOGObjectLevelArgs(@"EOEditingContext", @"Already inserted object [_unprocessedInserts] %p=%@", object, object); + } + + if ([gid isTemporary]) + { + [self _registerClearStateWithUndoManager]; + [_undoManager registerUndoWithTarget: self + selector: @selector(deleteObject:) + object: object]; + + gidBis = [self globalIDForObject: object]; + + if (!gidBis) + { + NSAssert(gid, @"No gid"); + + [self recordObject: object + globalID: gid]; + + NSHashInsert(_unprocessedInserts, object); + [self _enqueueEndOfEventNotification]; + } + } + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@", + [self unprocessedDescription]); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@", + [self objectsDescription]); + + EOFLOGObjectFnStop(); +} + +- (void) _processEndOfEventNotification: (NSNotification*)notification +{ + NSEmitTODO(); + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@", + [self unprocessedDescription]); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@", + [self objectsDescription]); + + if ([self tryLock]) + { + [self processRecentChanges]; + [self unlock]; + } + else + { + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + } + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@", + [self unprocessedDescription]); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@", + [self objectsDescription]); + + EOFLOGObjectFnStop(); +} + +- (void) noop: (id)param0 +{ + [self notImplemented: _cmd]; //TODO +} + +//"Receive NSUndoManagerCheckpointNotification Notification +- (void) _undoManagerCheckpoint: (NSNotification*)notification +{ + NSEmitTODO(); + + [self _processEndOfEventNotification: notification]; //OK +} + +- (BOOL) _processRecentChanges +{ + //Near OK for insert and update + BOOL result = YES; + + EOFLOGObjectFnStart(); + + if (!_flags.processingChanges) + { + NSArray *unprocessedInsertsArray = nil; + NSArray *unprocessedInsertsGlobalIDs = nil; + NSArray *unprocessedDeletesArray = nil; + NSArray *unprocessedDeletesGlobalIDs = nil; + NSArray *unprocessedChangesArray = nil; + NSArray *unprocessedChangesGlobalIDs = nil; + NSMutableDictionary *objectsArray = [NSMutableDictionary dictionary]; + NSMutableDictionary *objectGIDsArray = [NSMutableDictionary dictionary]; + int count = 0; + + _flags.processingChanges = YES; + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@", + [self unprocessedDescription]); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@", + [self objectsDescription]); + + [self _registerClearStateWithUndoManager]; + + //_undoManager isUndoing //ret NO //TODO + //_undoManager isRedoing //ret NO //TODO + [_undoManager beginUndoGrouping]; + + /*in undomanager beginUndoGrouping + [[NSNotificationCenter defaultCenter] postNotificationName:@"NSUndoManagerCheckpointNotification" + object:_undoManager]; //call _undoManagerCheckpoint: + [[NSNotificationCenter defaultCenter] postNotificationName:@"NSUndoManagerDidOpenUndoGroupNotification" + object:_undoManager]; + */ + + [self _processDeletedObjects]; + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@", + [self unprocessedDescription]); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@", + [self objectsDescription]); + + [_undoManager endUndoGrouping]; + + /*in undomanager endUndoGrouping + [[NSNotificationCenter defaultCenter] postNotificationName:@"NSUndoManagerCheckpointNotification" + object:_undoManager] //call _undoManagerCheckpoint: + [[NSNotificationCenter defaultCenter] postNotificationName:@"NSUndoManagerWillCloseUndoGroupNotification" + object:_undoManager]; + */ + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@", + [self unprocessedDescription]); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@", + [self objectsDescription]); + //on inserted objects + EOFLOGObjectLevelArgs(@"EOEditingContext", + @"process _unprocessedInserts"); + + unprocessedInsertsArray = NSAllHashTableObjects(_unprocessedInserts); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"unprocessedInsertsArray=%@", + unprocessedInsertsArray); + + [objectsArray setObject: unprocessedInsertsArray + forKey: @"inserted"]; + + unprocessedInsertsGlobalIDs + = [self resultsOfPerformingSelector: @selector(globalIDForObject:) + withEachObjectInArray: unprocessedInsertsArray]; + + [objectGIDsArray setObject: unprocessedInsertsGlobalIDs + forKey: @"inserted"]; + + count = [unprocessedInsertsArray count]; + + if (count > 0) + { + int i; + + for (i = 0; i < count; i++) + NSHashInsertIfAbsent(_insertedObjects, + [unprocessedInsertsArray objectAtIndex: i]); + + NSResetHashTable(_unprocessedInserts); + } + + //on deleted or updated + EOFLOGObjectLevelArgs(@"EOEditingContext", + @"process _unprocessedDeletes"); + + unprocessedDeletesArray = NSAllHashTableObjects(_unprocessedDeletes); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"unprocessedDeletesArray=%@", + unprocessedDeletesArray); + + [objectsArray setObject: unprocessedDeletesArray + forKey: @"deleted"]; + unprocessedDeletesGlobalIDs = [self resultsOfPerformingSelector: + @selector(globalIDForObject:) + withEachObjectInArray: + unprocessedDeletesArray]; + + [objectGIDsArray setObject: unprocessedDeletesGlobalIDs + forKey: @"deleted"]; + + count = [unprocessedDeletesArray count]; + + if (count > 0) + { + int i; + + for (i = 0; i < count; i++) + NSHashInsertIfAbsent(_deletedObjects, + [unprocessedDeletesArray objectAtIndex: i]); + + NSResetHashTable(_unprocessedDeletes); + } + + //Changes + EOFLOGObjectLevelArgs(@"EOEditingContext", + @"process _unprocessedChanges"); + + unprocessedChangesArray = NSAllHashTableObjects(_unprocessedChanges); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"unprocessedChangesArray=%@", + unprocessedChangesArray); + + [objectsArray setObject:unprocessedChangesArray + forKey:@"updated"]; + + unprocessedChangesGlobalIDs = [self resultsOfPerformingSelector: + @selector(globalIDForObject:) + withEachObjectInArray: + unprocessedChangesArray]; + + [objectGIDsArray setObject: unprocessedChangesGlobalIDs + forKey: @"updated"]; + + count = [unprocessedChangesArray count]; + + if (count > 0) + { + int i; + + for (i = 0; i < count; i++) + { + id object = [unprocessedChangesArray objectAtIndex: i]; + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"object=%p", object); + + if (!NSHashGet(_insertedObjects, object)) //Don't update inserted objects ?? + NSHashInsertIfAbsent(_changedObjects, object); + } + + NSResetHashTable(_unprocessedChanges); + } + + [EOObserverCenter notifyObserversObjectWillChange: nil]; + + [[NSNotificationCenter defaultCenter] + postNotificationName: @"EOObjectsChangedInStoreNotification" + object: self + userInfo: objectGIDsArray]; + + [[NSNotificationCenter defaultCenter] + postNotificationName: @"EOObjectsChangedInEditingContextNotification" + object: self + userInfo: objectsArray]; + + count = [unprocessedChangesArray count]; + + if (count > 0) + { + int i; + + for (i = 0; i < count; i++) + { + id object = [unprocessedChangesArray objectAtIndex: i]; + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"object=%p", object); + [self registerUndoForModifiedObject: object]; + } + } + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@", + [self unprocessedDescription]); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@", + [self objectsDescription]); + + _flags.processingChanges = NO; + } + + EOFLOGObjectFnStop(); + + return result; +/* + (count=0) + NSMutableDictionary *userInfo; + NSMutableArray *changedObjects, *invalidatedObjects; + NSMutableArray *objectsToRemove, *objectsToKeep; + NSEnumerator *objEnum; + NSException *exp; + NSArray *deletedObjects; + EOGlobalID *gid; + EONull *null = [EONull null]; + BOOL propagatesDeletes = YES, validateChanges = YES; + id object; + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"process recent changes"); + + objectsToKeep = [NSMutableArray arrayWithCapacity:8]; + objectsToRemove = [NSMutableArray arrayWithCapacity:8]; + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"process2"); + + objEnum = [NSAllHashTableObjects(_unprocessedChanges) objectEnumerator]; + while((object = [objEnum nextObject])) + { + NSDictionary *snapshot, *oldSnapshot, *changes; + NSArray *toRelArray; + NSEnumerator *toRelEnum; + NSString *key; + + gid = [self globalIDForObject:object]; + oldSnapshot = [_eventSnapshotsByGID objectForKey:gid]; + snapshot = [object snapshot]; + changes = [object changesFromSnapshot:oldSnapshot]; + + toRelArray = [object toOneRelationshipKeys]; + toRelEnum = [toRelArray objectEnumerator]; + while((key = [toRelEnum nextObject])) + { + id val = [changes objectForKey:key]; + + if(val == null) + val = nil; + + if(val && + [object ownsDestinationObjectsForRelationshipKey:key] == YES) + { + if(val != null) + [objectsToKeep addObject:val]; + + val = [oldSnapshot objectForKey:key]; + if(val != null) + [objectsToRemove addObject:val]; + } + } + + toRelArray = [object toManyRelationshipKeys]; + toRelEnum = [toRelArray objectEnumerator]; + while((key = [toRelEnum nextObject])) + { + NSArray *val = [changes objectForKey:key]; + + if(val == null) + val = nil; + + if(val && + [object ownsDestinationObjectsForRelationshipKey:key] == YES) + { + [objectsToKeep addObjectsFromArray:[val objectAtIndex:0]]; + [objectsToRemove addObjectsFromArray:[val objectAtIndex:0]]; + } + } + + [_eventSnapshotsByGID setObject:snapshot + forKey:gid]; + } + + [objectsToRemove removeObjectsInArray:objectsToKeep]; + objEnum = [objectsToRemove objectEnumerator]; + while((object = [objEnum nextObject])) + NSHashInsert(_unprocessedDeletes, object); + + deletedObjects = NSAllHashTableObjects(_unprocessedDeletes); + objEnum = [deletedObjects objectEnumerator]; + while((object = [objEnum nextObject])) + { + if(validateChanges) + { + +//in +validateTable:(NSHashTable*)table + withSelector:(SEL)sel + exceptionArray:(id*)param2 + continueAfterFailure: + exp = [object validateForDelete]; + + if(exp) // TODO + { + if(_flags.stopsValidation == NO) + { + if(_delegate == nil || + _delegateRespondsTo.shouldPresentException == NO || + (_delegateRespondsTo.shouldPresentException && + + [_delegate editingContext:self + shouldPresentException:exp] == YES)) + [_messageHandler editingContext:self + presentErrorMessage:[exp reason]]; + } + else + [exp raise]; + } + } +//fin in... + NSHashInsert(_deletedObjects, object); + + if(_undoManager) + [_undoManager registerUndoWithTarget:self + selector:@selector(_revertDelete:) + object:object]; + } + + +*/ + +/* +//propagatesDeletesUsingTable:(NSHashTable*)deleteTable + if(_flags.processingChanges == YES && + _delegateRespondsTo.shouldValidateChanges) + validateChanges = [_delegate editingContextShouldValidateChanges:self]; + + if(_flags.processingChanges == NO && [self propagatesDeletesAtEndOfEvent] == NO) + propagatesDeletes = NO; + + if(propagatesDeletes == YES) + { + if([self propagatesDeletesAtEndOfEvent] == YES) + objEnum = [NSAllHashTableObjects(_deletedObjects) objectEnumerator]; + else + objEnum = [NSAllHashTableObjects(_unprocessedDeletes) + objectEnumerator]; + + while((object = [objEnum nextObject])) + [object propagatesDeleteWithEditingContext:self]; + + if([self propagatesDeletesAtEndOfEvent] == YES) + { + objEnum = [NSAllHashTableObjects(_unprocessedDeletes) + objectEnumerator]; + while((object = [objEnum nextObject])) + NSHashInsert(_deletedObjects, object); + + deletedObjects = NSAllHashTableObjects(_deletedObjects); + } + else + deletedObjects = NSAllHashTableObjects(_unprocessedDeletes); + } + else + deletedObjects = NSAllHashTableObjects(_unprocessedDeletes); + + objEnum = [deletedObjects objectEnumerator]; + while((object = [objEnum nextObject])) + { + if(validateChanges) + { + exp = [object validateForDelete]; + + if(exp) // TODO + { + if(_flags.stopsValidation == NO) + { + if(_delegate == nil || + _delegateRespondsTo.shouldPresentException == NO || + (_delegateRespondsTo.shouldPresentException && + + [_delegate editingContext:self + shouldPresentException:exp] == YES)) + [_messageHandler editingContext:self + presentErrorMessage:[exp reason]]; + } + else + [exp raise]; + } + } + + if(propagatesDeletes == NO || [self propagatesDeletesAtEndOfEvent] == NO) + NSHashInsert(_deletedObjects, object); + + if(_undoManager) + [_undoManager registerUndoWithTarget:self + selector:@selector(_revertDelete:) + object:object]; + } +*/ + + + + +/* + EOFLOGObjectLevelArgs(@"EOEditingContext", @"process recent changes: prop delete"); + + objEnum = [NSAllHashTableObjects(_unprocessedChanges) objectEnumerator]; + while((object = [objEnum nextObject])) + { + if(validateChanges) + { + exp = [object validateForUpdate]; + + if(exp) + { + if(_flags.stopsValidation == NO) + { + if(_delegate == nil || + _delegateRespondsTo.shouldPresentException == NO || + (_delegateRespondsTo.shouldPresentException && + + [_delegate editingContext:self + shouldPresentException:exp] == YES)) + [_messageHandler editingContext:self + presentErrorMessage:[exp reason]]; + } + else + [exp raise]; + } + } + EOFLOGObjectLevelArgs(@"EOEditingContext", @"** add changed"); + NSHashInsert(_changedObjects, object); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"** add changed2"); + + if(_undoManager) + [_undoManager registerUndoWithTarget:self + selector:@selector(_revertChanged:) // TODO si pianta + object:object]; + EOFLOGObjectLevelArgs(@"EOEditingContext", @"** add changed: undo"); + } + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"process recent changes: validated changes"); + + objEnum = [NSAllHashTableObjects(_unprocessedInserts) objectEnumerator]; + while((object = [objEnum nextObject])) + { + if(validateChanges) + { + exp = [object validateForInsert]; + + if(exp) + { + if(_flags.stopsValidation == NO) + { + if(_delegate == nil || + _delegateRespondsTo.shouldPresentException == NO || + (_delegateRespondsTo.shouldPresentException && + + [_delegate editingContext:self + shouldPresentException:exp] == YES)) + [_messageHandler editingContext:self + presentErrorMessage:[exp reason]]; + } + else + [exp raise]; + } + } + + NSHashInsert(_insertedObjects, object); + + if(_undoManager) + [_undoManager registerUndoWithTarget:self + selector:@selector(_revertInsert:) + object:object]; + } + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"process recent changes: validated inserts"); + + [_undoManager endUndoGrouping]; + [_undoManager beginUndoGrouping]; + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"process recent changes: end undo"); + + userInfo = [NSMutableDictionary dictionaryWithCapacity:3]; + + changedObjects = [NSMutableArray arrayWithCapacity:8]; + objEnum = [NSAllHashTableObjects(_unprocessedDeletes) objectEnumerator]; + while((object = [objEnum nextObject])) + [changedObjects addObject:[self globalIDForObject:object]]; + + [userInfo setObject:changedObjects + forKey:EODeletedKey]; + + changedObjects = [NSMutableArray arrayWithCapacity:8]; + objEnum = [NSAllHashTableObjects(_unprocessedInserts) objectEnumerator]; + while((object = [objEnum nextObject])) + [changedObjects addObject:[self globalIDForObject:object]]; + + [userInfo setObject:changedObjects + forKey:EOInsertedKey]; + + invalidatedObjects = [NSMutableArray arrayWithCapacity:8]; + changedObjects = [NSMutableArray arrayWithCapacity:8]; + + objEnum = [NSAllHashTableObjects(_changedObjects) objectEnumerator]; + while((object = [objEnum nextObject])) + { + if([EOFault isFault:object] == YES) + [invalidatedObjects addObject:[self globalIDForObject:object]]; + else + [changedObjects addObject:[self globalIDForObject:object]]; + } + + [userInfo setObject:changedObjects + forKey:EOUpdatedKey]; + [userInfo setObject:invalidatedObjects + forKey:EOInvalidatedKey]; + + [[NSNotificationCenter defaultCenter] + postNotificationName:EOObjectsChangedInStoreNotification + object:self + userInfo:userInfo]; + + userInfo = [NSMutableDictionary dictionaryWithCapacity:3]; + + [userInfo setObject:NSAllHashTableObjects(_unprocessedDeletes) + forKey:EODeletedKey]; + [userInfo setObject:NSAllHashTableObjects(_unprocessedInserts) + forKey:EOInsertedKey]; + + invalidatedObjects = [NSMutableArray arrayWithCapacity:8]; + changedObjects = [NSMutableArray arrayWithCapacity:8]; + + objEnum = [NSAllHashTableObjects(_unprocessedChanges) objectEnumerator]; + while((object = [objEnum nextObject])) + { + if([EOFault isFault:object] == YES) + [invalidatedObjects addObject:object]; + else + [changedObjects addObject:object]; + } + + [userInfo setObject:changedObjects + forKey:EOUpdatedKey]; + [userInfo setObject:invalidatedObjects + forKey:EOInvalidatedKey]; + + [[NSNotificationCenter defaultCenter] + postNotificationName:EOObjectsChangedInEditingContextNotification + object:self + userInfo:userInfo]; + + NSResetHashTable(_unprocessedChanges); + NSResetHashTable(_unprocessedDeletes); + NSResetHashTable(_unprocessedInserts); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"** process finished"); + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"process recent changes END"); +*/ +} + +- (void) _processDeletedObjects +{ + //OK finished ?? + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@", + [self unprocessedDescription]); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@", + [self objectsDescription]); + + [self _processOwnedObjectsUsingChangeTable: _unprocessedChanges + deleteTable: _unprocessedDeletes]; + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@", + [self unprocessedDescription]); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@", + [self objectsDescription]); + + [self propagatesDeletesUsingTable: _unprocessedDeletes]; + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@", + [self unprocessedDescription]); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@", + [self objectsDescription]); + [self validateDeletesUsingTable: _unprocessedDeletes]; + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@", + [self unprocessedDescription]); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@", + [self objectsDescription]); + + EOFLOGObjectFnStop(); +} + +/* + +//verify + BOOL propagatesDeletes = YES, validateChanges = YES; + if(_flags.processingChanges == YES + && _delegateRespondsTo.shouldValidateChanges) + validateChanges = [_delegate editingContextShouldValidateChanges:self]; + + if(_flags.processingChanges == NO && [self propagatesDeletesAtEndOfEvent] == NO) + propagatesDeletes = NO; + + if(propagatesDeletes == YES) + { + if([self propagatesDeletesAtEndOfEvent] == YES) + objEnum = [NSAllHashTableObjects(_deletedObjects) objectEnumerator]; + else + objEnum = [NSAllHashTableObjects(_unprocessedDeletes) + objectEnumerator]; + + while((object = [objEnum nextObject])) + [object propagatesDeleteWithEditingContext:self]; + + if([self propagatesDeletesAtEndOfEvent] == YES) + { + objEnum = [NSAllHashTableObjects(_unprocessedDeletes) + objectEnumerator]; + while((object = [objEnum nextObject])) + NSHashInsert(_deletedObjects, object); + + deletedObjects = NSAllHashTableObjects(_deletedObjects); + } + else + deletedObjects = NSAllHashTableObjects(_unprocessedDeletes); + } + else + deletedObjects = NSAllHashTableObjects(_unprocessedDeletes); + + objEnum = [deletedObjects objectEnumerator]; + while((object = [objEnum nextObject])) + { + if(validateChanges) + { + exp = [object validateForDelete]; + + if(exp) // TODO + { + if(_flags.stopsValidation == NO) + { + if(_delegate == nil || + _delegateRespondsTo.shouldPresentException == NO || + (_delegateRespondsTo.shouldPresentException && + + [_delegate editingContext:self + shouldPresentException:exp] == YES)) + [_messageHandler editingContext:self + presentErrorMessage:[exp reason]]; + } + else + [exp raise]; + } + } + + if(propagatesDeletes == NO || [self propagatesDeletesAtEndOfEvent] == NO) + NSHashInsert(_deletedObjects, object); + + if(_undoManager) + [_undoManager registerUndoWithTarget:self + selector:@selector(_revertDelete:) + object:object]; + } + +} +*/ + +- (void)validateChangesForSave +{ + NSMutableArray *exceptions = nil; + BOOL validateForDelete = NO; + + EOFLOGObjectFnStart(); + + validateForDelete = [self validateTable: _unprocessedDeletes + withSelector: @selector(validateForDelete) + exceptionArray: &exceptions + continueAfterFailure: NO]; + + if (!validateForDelete) + { + switch ([exceptions count]) + { + case 1: + [[exceptions objectAtIndex: 0] raise]; + break; + case 0: + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + break; + default: + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + break; + } + } + else + { + BOOL validateForInsert = [self validateTable: _unprocessedInserts + withSelector: @selector(validateForInsert) + exceptionArray: &exceptions + continueAfterFailure: NO]; + + if (!validateForInsert) + { + switch ([exceptions count]) + { + case 1: + [[exceptions objectAtIndex: 0] raise]; + break; + case 0: + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + break; + default: + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + break; + } + } + else + { + BOOL validateForUpdate + = [self validateTable: _unprocessedInserts + withSelector: @selector(validateForUpdate) + exceptionArray: &exceptions + continueAfterFailure: NO]; + + if (!validateForUpdate) + { + switch ([exceptions count]) + { + case 1: + [[exceptions objectAtIndex: 0] raise]; + break; + case 0: + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + break; + default: + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + break; + } + } + } + } + + EOFLOGObjectFnStop(); +} + +- (void) validateDeletesUsingTable: (NSHashTable*)deleteTable +{ + NSMutableArray *exceptionArray = nil; + + if (![self validateTable: deleteTable + withSelector: @selector(validateForDelete) + exceptionArray: &exceptionArray + continueAfterFailure: NO]) + { + NSException *exception = [NSException aggregateExceptionWithExceptions: + exceptionArray]; + [exception raise]; + } +} + +- (BOOL) validateTable: (NSHashTable*)table + withSelector: (SEL)sel + exceptionArray: (NSMutableArray**)exceptionArrayPtr + continueAfterFailure: (BOOL)continueAfterFailure +{ + BOOL ok = YES; + NSHashEnumerator enumerator; + id object = nil; + + EOFLOGObjectFnStart(); + + enumerator = NSEnumerateHashTable(table); + + while ((ok || continueAfterFailure) + && (object=(id)NSNextHashEnumeratorItem(&enumerator))) + { + NSException *exception = [object performSelector: sel]; + + if (exception) + { + ok = NO; + if (continueAfterFailure) + { + if (_delegate == nil + || _delegateRespondsTo.shouldPresentException == NO + || (_delegateRespondsTo.shouldPresentException + && [_delegate editingContext: self + shouldPresentException: exception] == YES)) + [_messageHandler editingContext: self + presentErrorMessage: [exception reason]]; + } + + if (exceptionArrayPtr) + { + if (!*exceptionArrayPtr) + *exceptionArrayPtr = [NSMutableArray array]; + + [*exceptionArrayPtr addObject: exception]; + } + } + } + +// NSEndHashTableEnumeration(enumerator); + EOFLOGObjectFnStop(); + + return ok; +} + +- (BOOL) handleErrors: (id)p +{ + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + + return NO; +} + +- (BOOL) handleError: (NSException*)exception +{ + [exception raise]; //raise the exception?? + + return NO; +} + +- (void) propagatesDeletesUsingTable: (NSHashTable*)deleteTable +{ + NSHashEnumerator enumerator; + id object = nil; + + EOFLOGObjectFnStart(); + + enumerator = NSEnumerateHashTable(deleteTable); + + while ((object = (id)NSNextHashEnumeratorItem(&enumerator))) + [object propagateDeleteWithEditingContext: self]; + + EOFLOGObjectFnStop(); +} + +- (void) _processOwnedObjectsUsingChangeTable: (NSHashTable*)changeTable + deleteTable: (NSHashTable*)deleteTable +{ + NSHashTable *objectsToInsert = NSCreateHashTable(NSObjectHashCallBacks, 32); + NSHashEnumerator enumerator; + id object = nil; + + EOFLOGObjectFnStart(); + + enumerator = NSEnumerateHashTable(changeTable); + + while ((object = (id)NSNextHashEnumeratorItem(&enumerator))) + { + NSDictionary *objectSnapshot = nil; + NSArray *toOneRelationshipKeys; + NSArray *toManyRelationshipKeys = nil; + int i; + int count; + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"object:%@", object); + + toOneRelationshipKeys = [object toOneRelationshipKeys]; + EOFLOGObjectLevelArgs(@"EOEditingContext", @"toOneRelationshipKeys:%@", + toOneRelationshipKeys); + + count = [toOneRelationshipKeys count]; + + for (i = 0; i < count; i++) + { + NSString *relKey = [toOneRelationshipKeys objectAtIndex: i]; + BOOL ownsDestinationObjects + = [object ownsDestinationObjectsForRelationshipKey:relKey]; + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"relKey:%@", relKey); + EOFLOGObjectLevelArgs(@"EOEditingContext", + @"ownsDestinationObjects: %s", + (ownsDestinationObjects ? "YES" : "NO")); + + if (ownsDestinationObjects) + { + id existingObject = nil; + id value = nil; + + if (!objectSnapshot) + objectSnapshot = [self currentEventSnapshotForObject: object]; + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"objectSnapshot:%@", + objectSnapshot); + + existingObject = [objectSnapshot objectForKey: relKey]; + EOFLOGObjectLevelArgs(@"EOEditingContext", @"existingObject:%@", + existingObject); + + value = [object storedValueForKey: relKey]; + EOFLOGObjectLevelArgs(@"EOEditingContext", @"value:%@", value); + + if (value != existingObject) + { + if (isNilOrEONull(value)) + { + if (!isNilOrEONull(existingObject))//value is new + { + //existing object is removed + //TODO ?? ad it in delete table ?? + NSEmitTODO(); + [self notImplemented:_cmd]; //TODO + } + } + else + { + if (!isNilOrEONull(existingObject))//value is new + { + //existing object is removed + //TODO ?? ad it in delete table ?? + NSEmitTODO(); + [self notImplemented:_cmd]; //TODO + } + if (!NSHashGet(changeTable,value))//id not already in change table + { + //We will insert it + NSHashInsertIfAbsent(objectsToInsert,value); + EOFLOGObjectLevelArgs(@"EOEditingContext",@"Will insert %@",value); + } + } + } + } + } + + toManyRelationshipKeys = [object toManyRelationshipKeys]; + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"object:%@", object); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"toManyRelationshipKeys: %@", + toManyRelationshipKeys); + + count = [toManyRelationshipKeys count]; + + for (i = 0; i < count; i++) + { + NSString *relKey = [toManyRelationshipKeys objectAtIndex: i]; //1-1 payments + BOOL ownsDestinationObjects + = [object ownsDestinationObjectsForRelationshipKey: relKey]; + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"relKey: %@", relKey); + EOFLOGObjectLevelArgs(@"EOEditingContext", + @"ownsDestinationObjects: %s", + (ownsDestinationObjects ? "YES" : "NO")); + + if (ownsDestinationObjects) //1-1 YES + { + NSArray *existingObjects = nil; + NSArray *currentObjects = nil; + NSArray *newObjects = nil; + int newObjectsCount = 0; + int iNewObject = 0; + + if (!objectSnapshot) + objectSnapshot = [self currentEventSnapshotForObject: object]; + + EOFLOGObjectLevelArgs(@"EOEditingContext", + @"objectSnapshot:%p: %@", + objectSnapshot, objectSnapshot); + + existingObjects = [objectSnapshot objectForKey: relKey]; + EOFLOGObjectLevelArgs(@"EOEditingContext", + @"key %@ existingObjects: %@", + relKey, existingObjects); + + currentObjects = [object storedValueForKey: relKey]; + EOFLOGObjectLevelArgs(@"EOEditingContext", + @"key %@ currentObjects: %@", + relKey, currentObjects); +//TODO YY=[currentObjects shallowCopy]; + + newObjects = [currentObjects arrayExcludingObjectsInArray: + existingObjects]; + EOFLOGObjectLevelArgs(@"EOEditingContext", @"newObjects: %@", + newObjects); + + newObjectsCount = [newObjects count]; + + for (iNewObject = 0; iNewObject < newObjectsCount; iNewObject++) + { + id newObject = [newObjects objectAtIndex: iNewObject]; + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"newObject: %@", + newObject); + + if (!NSHashGet(changeTable, newObject)) //id not already in change table (or in insertTable ?) + { + //We will insert it + NSHashInsertIfAbsent(objectsToInsert, newObject); + EOFLOGObjectLevelArgs(@"EOEditingContext", + @"Will insert %@", newObject); + } + } + +//TODO XX=[existingObjects arrayExcludingObjectsInArray:(newObjects or currentObjects)];//nil +//=========> + NSEmitTODO(); +//TODO [self notImplemented:_cmd]; //TODO + } + } + } + + enumerator = NSEnumerateHashTable(objectsToInsert); + + while ((object = (id)NSNextHashEnumeratorItem(&enumerator))) + { + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Insert %@", object); + [self insertObject: object]; + } + + NSFreeHashTable(objectsToInsert); + + //TODO-NOW: use deleteTable ! + //[self notImplemented:_cmd]; //TODO + + EOFLOGObjectFnStop(); +} + +- (void) registerUndoForModifiedObject: (id)object +{ + EOGlobalID *gid; + NSDictionary *snapshot; + NSDictionary *undoObject; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"object=%@", object); + + gid = [self globalIDForObject: object]; + EOFLOGObjectLevelArgs(@"EOEditingContext", @"gid=%@", gid); + + snapshot = [self currentEventSnapshotForObject: object]; + undoObject = [NSDictionary dictionaryWithObjectsAndKeys: + object, @"object", + snapshot, @"snapshot", + nil, nil]; + + [_undoManager registerUndoWithTarget: self + selector: @selector(_undoUpdate:) + object: undoObject]; + + [_eventSnapshotsByGID removeObjectForKey: gid]; + + EOFLOGObjectFnStop(); +} + +- (void) _undoUpdate: (id)param0 +{ + NSEmitTODO(); + //TODO +// receive a dict with object and snapshot ? (cf registerUndoForModifiedObject:) +} + +- (void)incrementUndoTransactionID +{ + _undoTransactionID++; + _flags.registeredUndoTransactionID = NO; +} + +- (void) _registerClearStateWithUndoManager +{ +//pas appellé dans le cas d'un delete ? + id object; + + EOFLOGObjectFnStart(); + + object = [NSNumber numberWithUnsignedInt: _undoTransactionID]; + _flags.registeredUndoTransactionID = YES; + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"_undoManager=%p", _undoManager); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"_undoManager=%@", _undoManager); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"self=%@", self); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"object=%@", object); + + [_undoManager registerUndoWithTarget: self + selector: @selector(_clearChangedThisTransaction:) + object: object]; + + EOFLOGObjectFnStop(); +} + +- (void)deleteObject: (id)object +{ + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"object=%@", object); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@", + [self unprocessedDescription]); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@", + [self objectsDescription]); + + if (!NSHashGet(_unprocessedDeletes, object) + && !NSHashGet(_deletedObjects, object)) + { + NSMethodSignature *undoMethodSignature = nil; + EOUndoManager *undoManager; + //EOGlobalID *gid = [self globalIDForObject: object]; + + [self _registerClearStateWithUndoManager]; + + undoManager = (EOUndoManager*)[self undoManager]; + [undoManager prepareWithInvocationTarget: self]; + + undoMethodSignature = [undoManager methodSignatureForSelector: + @selector(_insertObject:withGlobalID:)]; + /* + //TODO + if base class of undoManager ret nil, undomanager call editingcont methodSignatureForSelector: _insertObject:withGlobalID: + + undoManager forwardInvocation: + + _NSUndoInvocation avec selector:_insertObject:withGlobalID: + target self (editing context) + [undoManager _registerUndoObject:arget: EOEditingContext -- selector:_insertObject:withGlobalID: + _invocation=NSInvocation * object: Description: + next=_NSUndoObject * object:0x0 Description:*nil* + previous=_NSUndoObject * object:0x0 Description:*nil* + _target=id object: Description: + [self _prepareEventGrouping]; +*/ + + NSHashInsert(_unprocessedDeletes, object); + [self _enqueueEndOfEventNotification]; + } + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@", + [self unprocessedDescription]); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@", + [self objectsDescription]); + + EOFLOGObjectFnStop(); +} + +- (void)lockObject: (id)object +{ + EOGlobalID *gid = [self globalIDForObject: object]; + + if (gid == nil) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: globalID for object 0x%x not found", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + object]; + + [self lockObjectWithGlobalID: gid + editingContext: self]; +} + +// Saving +- (BOOL)hasChanges +{ + if(NSCountHashTable(_insertedObjects) + || NSCountHashTable(_deletedObjects) + || NSCountHashTable(_changedObjects)) + return YES; + + return NO; +} + +- (void)didSaveChanges +{ + NSHashTable *hashTables[3]={ _insertedObjects, + _deletedObjects,//?? + _changedObjects }; + NSMutableArray *objectsForNotification[3]={ [NSMutableArray array],//inserted + [NSMutableArray array],//deleted + [NSMutableArray array] };//updated + NSEnumerator *enumerator = nil; + id object = nil; + int which; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOEditingContext", + @"Changes nb: inserted:%d deleted:%d changed:%d", + NSCountHashTable(_insertedObjects), + NSCountHashTable(_deletedObjects), + NSCountHashTable(_changedObjects)); + + _flags.ignoreChangeNotification=NO; //MG?? + + for (which = 0; which < 3; which++) + { + NSHashEnumerator hashEnumerator = NSEnumerateHashTable(hashTables[which]); + + while ((object = (id)NSNextHashEnumeratorItem(&hashEnumerator))) + { + [objectsForNotification[which] addObject: object]; + [self clearOriginalSnapshotForObject: object]; //OK for update + } + } + + enumerator = [NSAllHashTableObjects(_deletedObjects) objectEnumerator]; + while ((object = [enumerator nextObject])) + { + [self forgetObject: object]; + [object clearProperties]; + } + + NSResetHashTable(_insertedObjects); + NSResetHashTable(_deletedObjects); + NSResetHashTable(_changedObjects); + [self incrementUndoTransactionID]; //OK for update + + { + EOGlobalID *gid; + + enumerator = [[_snapshotsByGID allKeys] objectEnumerator]; + + while ((gid = [enumerator nextObject])) + { + [_snapshotsByGID setObject: [[self objectForGlobalID:gid] snapshot] + forKey: gid]; + } + } + + [[NSNotificationCenter defaultCenter] + postNotificationName: @"EOEditingContextDidSaveChangesNotification" + object: self + userInfo: [NSDictionary dictionaryWithObjectsAndKeys: + objectsForNotification[0], @"inserted", + objectsForNotification[1], @"deleted", + objectsForNotification[2], @"updated", + nil, nil]]; + + EOFLOGObjectFnStop(); +} + +- (void)saveChanges +{ + id object = nil; + NSEnumerator *enumerator; + + EOFLOGObjectFnStart(); + + //TODOLOCK + [self lock]; + + NS_DURING + { + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@", + [self unprocessedDescription]); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@", + [self objectsDescription]); + + enumerator = [_editors objectEnumerator]; + + while ((object = [enumerator nextObject])) + [object editingContextWillSaveChanges: self]; + + if (_delegateRespondsTo.willSaveChanges) + [_delegate editingContextWillSaveChanges: self]; + + [self _processRecentChanges]; // filled lists _changedObjects, _deletedObjects, _insertedObjects, breaks relations + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@", + [self unprocessedDescription]); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@", + [self objectsDescription]); + + _flags.registeredForCallback = NO; + + [self validateChangesForSave]; // may raise exception + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@", + [self unprocessedDescription]); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@", + [self objectsDescription]); + //?? [EOObserverCenter notifyObserversObjectWillChange: nil]; + + _flags.ignoreChangeNotification = YES; + + EOFLOGObjectLevelArgs(@"EOEditingContext", + @"_objectStore saveChangesInEditingContext"); + + [_objectStore saveChangesInEditingContext: self]; + EOFLOGObjectLevelArgs(@"EOEditingContext", @"self didSaveChanges"); + + [self didSaveChanges]; + + EOFLOGObjectFnStop(); + } + NS_HANDLER + { + NSLog(@"%@ (%@)", localException, [localException reason]); + NSDebugMLog(@"%@ (%@)", localException, [localException reason]); + + [self unlock]; + [localException raise]; + } + NS_ENDHANDLER; + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@", + [self unprocessedDescription]); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@", + [self objectsDescription]); + + [self unlock]; +} + +- (NSException *) tryToSaveChanges +{ + NSException *newException = nil; + + EOFLOGObjectFnStartOrCond(@"EOEditingContext"); + + NS_DURING + { + [self saveChanges]; + } + NS_HANDLER + { + if(_messageHandler + && [_messageHandler + respondsTo: @selector(editingContext:presentErrorMessage:)] == YES) + [_messageHandler editingContext: self + presentErrorMessage: [localException reason]]; + + newException = localException; + } + NS_ENDHANDLER; + + EOFLOGObjectFnStopOrCond(@"EOEditingContext"); + + return newException; +} + +- (void)revert +{ + NSEnumerator *enumerator; + EOGlobalID *gid; + + enumerator = [_eventSnapshotsByGID keyEnumerator]; + while ((gid = [enumerator nextObject])) + { + [[self objectForGlobalID: gid] + updateFromSnapshot: [_eventSnapshotsByGID objectForKey: gid]]; + } + +#if 0 + [_undoManager removeAllActions]; + [_undoManager beginUndoGrouping]; +#endif + + NSResetHashTable(_unprocessedChanges); + NSResetHashTable(_unprocessedDeletes); + NSResetHashTable(_unprocessedInserts); + + NSResetHashTable(_changedObjects); + NSResetHashTable(_deletedObjects); + NSResetHashTable(_insertedObjects); +} + +- (void) clearOriginalSnapshotForObject: (id)object +{ + //Consider OK + EOGlobalID *gid = [self globalIDForObject: object]; + + if (gid) + { + [_snapshotsByGID removeObjectForKey: gid]; + } +} + +- (id)objectForGlobalID:(EOGlobalID *)globalID +{ + id object; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"gid=%@", globalID); +// NSDebugMLLog(@"XXX",@"_objectsByGID=%@",NSAllMapTableKeys(_objectsByGID)); + + object = NSMapGet(_objectsByGID, globalID); + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"object=%p", object); + + EOFLOGObjectFnStop(); + + return object; +} + +- (EOGlobalID *)globalIDForObject: (id)object +{ + //Consider OK + EOGlobalID *gid; + + /* + [self recordForObject:object] + [self notImplemented:_cmd]; //TODO + */ + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOEditingContext", + @"ed context=%p _objectsById=%p object=%p", + self, _objectsById, object); +// EOFLOGObjectLevelArgs(@"EOEditingContext",@"_objectsById Values=%@",NSAllMapTableValues(_objectsById)); + + gid = NSMapGet(_objectsById, object); + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"gid=%@", gid); + + EOFLOGObjectFnStop(); + + return gid; +} + +- (NSHashTable*) recordForGID: (EOGlobalID *)globalID +{ + [self notImplemented: _cmd]; //TODO + return NULL; +} + +- (NSHashTable*) recordForObject: (id)object +{ + [self notImplemented: _cmd]; //TODO + return NULL; +} + +- (void)setDelegate: (id)delegate +{ + _delegate = delegate; + _delegateRespondsTo.willRunLoginPanel = + [delegate respondsToSelector: @selector(databaseContext:willRunLoginPanelToOpenDatabaseChannel:)]; + _delegateRespondsTo.shouldFetchObjects = + [delegate respondsToSelector: @selector(editingContext:shouldFetchObjectsDescribedByFetchSpecification:)]; + _delegateRespondsTo.shouldInvalidateObject = + [delegate respondsToSelector: @selector(editingContext:shouldInvalidateObject:globalID:)]; + _delegateRespondsTo.shouldMergeChanges = + [delegate respondsToSelector: @selector(editingContext:shouldMergeChangesForObject:)]; + _delegateRespondsTo.shouldPresentException = + [delegate respondsToSelector: @selector(editingContext:shouldPresentException:)]; + _delegateRespondsTo.shouldUndoUserActions = + [delegate respondsToSelector: @selector(editingContextShouldUndoUserActionsAfterFailure:)]; + _delegateRespondsTo.shouldValidateChanges = + [delegate respondsToSelector: @selector(editingContextShouldValidateChanges:)]; + _delegateRespondsTo.willSaveChanges = + [delegate respondsToSelector: @selector(editingContextWillSaveChanges:)]; +} + +- (id)delegate +{ + return _delegate; +} + +- (EOObjectStore *)parentObjectStore +{ + return _objectStore; +} + +- (EOObjectStore *)rootObjectStore +{ + EOObjectStore *rootObjectStore; + + EOFLOGObjectFnStart(); + + if ([_objectStore isKindOfClass: [EOEditingContext class]] == YES) + rootObjectStore = [(EOEditingContext *)_objectStore rootObjectStore]; + else + rootObjectStore=_objectStore; + + EOFLOGObjectFnStop(); + + return rootObjectStore; +} + + +// Advanced methods ////////////////////////// + +- (void)setUndoManager: (NSUndoManager *)undoManager +{ + ASSIGN(_undoManager, undoManager); +} + +- (NSUndoManager *)undoManager +{ + return _undoManager; +} + +- (void)_revertChange: (NSDictionary *)dict +{ + [[dict objectForKey: @"object"] + updateFromSnapshot: [dict objectForKey: @"snapshot"]]; +} + +- (void)objectWillChange: (id)object +{ + EOFLOGObjectFnStart(); + +// EOFLOGObjectLevelArgs(@"EOEditingContext", @"object=%@", object); + EOFLOGObjectLevelArgs(@"EOEditingContext", + @"object=%@ _flags.ignoreChangeNotification=%d", + object, (int)_flags.ignoreChangeNotification); + + if (_flags.ignoreChangeNotification == NO) + { + NSDictionary *snapshot; + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"*** object change %p %@", + object, [object class]); + //recordForObject: + + snapshot = [object snapshot]; // OK + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"snapshot=%@", snapshot); +//if not in _unprocessedChanges: add in snaps and call _enqueueEndOfEventNotification +/* +[_undoManager registerUndoWithTarget:self + selector:@selector(noop:) + object:nil;]; +*/ +//////// + if (NSHashInsertIfAbsent(_unprocessedChanges, object)) //The object is already here + { + EOFLOGObjectLevelArgs(@"EOEditingContext", + @"_enqueueEndOfEventNotification"); + [self _enqueueEndOfEventNotification]; + + /* + if(_undoManager) + [_undoManager registerUndoWithTarget:self + selector:@selector(_revertChange:) + object:[NSDictionary dictionaryWithObjectsAndKeys: + object, @"object", + [object snapshot], @"snapshot", + nil]]; + */ + } + else + { + //??????????? + EOGlobalID *gid = [self globalIDForObject: object]; + + EOFLOGObjectLevelArgs(@"EOEditingContext", + @"insert into xxsnapshotsByGID"); + + [_eventSnapshotsByGID setObject: [object snapshot] + forKey: gid]; + + [_snapshotsByGID setObject: [object snapshot] + forKey: gid]; + + if (_flags.autoLocking == YES) + [self lockObject: object]; + } + } + + EOFLOGObjectFnStop(); +} + +- (void)recordObject: (id)object + globalID: (EOGlobalID *)globalID +{ + //OK + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOEditingContext", + @"Record %p for %@ in ed context %p _objectsById=%p", + object, globalID, self, _objectsById); + + NSAssert(object, @"No Object"); + NSAssert(globalID, @"No GlobalID"); + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"insertInto _objectsById"); + NSMapInsert(_objectsById, object, globalID); + + //TODO: delete + { + id aGID2; + id aGID = NSMapGet(_objectsById, object); + + NSAssert1(aGID, @"Object %p recorded but can't retrieve it directly !", + object); + + aGID2 = [self globalIDForObject: object]; + + NSAssert1(aGID2, @"Object %p recorded but can't retrieve it with globalIDForObject: !", object); + } + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"insertInto _objectsByGID"); + + NSMapInsert(_objectsByGID, globalID, object); + + EOFLOGObjectLevelArgs(@"EOEditingContext", @"addObserver"); + + [EOObserverCenter addObserver: self + forObject: object]; +//call EOAccessFaultHandler targetClass + EOFLOGObjectFnStop(); +} + +- (void)forgetObject: (id)object +{ + EOGlobalID *gid; + + gid = [self globalIDForObject: object]; + NSMapRemove(_objectsById, object); + NSMapRemove(_objectsByGID, gid); + + [EOObserverCenter removeObserver: self + forObject: object]; +} + +- (NSArray *)registeredObjects +{ + return NSAllMapTableValues(_objectsByGID); +} + +- (NSArray *)updatedObjects +{ + NSMutableArray *updatedObjects = [NSMutableArray array]; + NSHashEnumerator changedEnum = NSEnumerateHashTable(_changedObjects); + id object; + + while ((object = (id)NSNextHashEnumeratorItem(&changedEnum))) + { + if (!NSHashGet(_deletedObjects, (const void*)object)) + [updatedObjects addObject: object]; + } + +// NSEndHashTableEnumeration(changedEnum); + + return updatedObjects; +} + +- (NSArray *)insertedObjects +{ + return NSAllHashTableObjects(_insertedObjects); + //TODO: remove inserted objectss which are deleted ??? +} + +- (NSArray *)deletedObjects +{ + return NSAllHashTableObjects(_deletedObjects); +} + + +- (void)_revertInsert: (id)object +{ + NSHashRemove(_insertedObjects, object); +} + +- (void)_revertUpdate: (id)object +{ + NSHashRemove(_changedObjects, object); +} + +- (void)_revertDelete: (id)object +{ + NSHashRemove(_deletedObjects, object); +} + +// *************************** +// * +// * Objects for DELETE +// * +// * compares object from _unprocessedChanges +// * between their state from _eventSnapshots and [object snapshot] +// * +// * you can see if any other instead of this EditingContext has changed the object +// * +// * decision of keeping or deleting these changed objects (RelationshipObjects) +// * +// **************************** +- (void)processRecentChanges +{ + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Unprocessed: %@", + [self unprocessedDescription]); + EOFLOGObjectLevelArgs(@"EOEditingContext", @"Objects: %@", + [self objectsDescription]); + NSEmitTODO(); + +// [self notImplemented:_cmd]; //TODO + [self _processRecentChanges]; //ret YES +} + +- (BOOL)propagatesDeletesAtEndOfEvent +{ + return _flags.propagatesDeletesAtEndOfEvent; +} + +- (void)setPropagatesDeletesAtEndOfEvent: (BOOL)propagatesDeletesAtEndOfEvent +{ + _flags.propagatesDeletesAtEndOfEvent = propagatesDeletesAtEndOfEvent; +} + +- (BOOL)stopsValidationAfterFirstError +{ + return !_flags.exhaustiveValidation; +} + +- (void)setStopsValidationAfterFirstError:(BOOL)flag +{ + _flags.exhaustiveValidation = !flag; +} + +- (BOOL)locksObjectsBeforeFirstModification +{ + return _flags.autoLocking; +} + +- (void)setLocksObjectsBeforeFirstModification: (BOOL)flag +{ + _flags.autoLocking = flag; +} + + +// Snapshotting + +/** Returns a dictionary containing a snapshot of object that +reflects its committed values (last values putted in the +database; i.e. values before changes were made on the object). +It is updated after commiting new values. +**/ + +- (NSDictionary *)committedSnapshotForObject: (id)object +{ + //OK + return [_snapshotsByGID objectForKey: [self globalIDForObject: object]]; +} + +/** Returns a dictionary containing a snapshot of object with +its state as it was at the beginning of the current event loop. +After the end of the current event, upon invocation of +processRecentChanges, the snapshot is updated to hold the +modified state of the object.**/ +- (NSDictionary *)currentEventSnapshotForObject: (id)object +{ + //OK + return [_eventSnapshotsByGID objectForKey: [self globalIDForObject: object]]; +} + +- (NSDictionary *)uncommittedChangesForObject: (id)object +{ + return [object changesFromSnapshot: + [self currentEventSnapshotForObject: object]]; +} + +- (void)refaultObjects +{ + NSMutableArray *objs = [[NSMutableArray new] autorelease]; + NSEnumerator *objsEnum; + id obj; + + [self processRecentChanges]; + + [objs addObjectsFromArray: NSAllMapTableKeys(_objectsById)]; + + [objs removeObjectsInArray: [self insertedObjects]]; + [objs removeObjectsInArray: [self deletedObjects]]; + [objs removeObjectsInArray: [self updatedObjects]]; + + objsEnum = [objs objectEnumerator]; + + while ((obj = [objsEnum nextObject])) + [self refaultObject: obj + withGlobalID: [self globalIDForObject: obj] + editingContext: self]; +} + +// Refaults all objects that haven't been modified, inserted or deleted. + +- (void)setInvalidatesObjectsWhenFreed: (BOOL)flag +{ + _flags.skipInvalidateOnDealloc = flag; +} + +- (BOOL)invalidatesObjectsWhenFreed +{ + return _flags.skipInvalidateOnDealloc; // TODO contrario ?? +} + +- (void)addEditor: (id)editor +{ + [_editors addObject: editor]; +} + +- (void)removeEditor: (id)editor +{ + [_editors removeObject: editor]; +} + +- (NSArray *)editors +{ + return _editors; +} + +- (void)setMessageHandler: (id)handler +{ + _messageHandler = handler; +} + +- (id)messageHandler +{ + return _messageHandler; +} + +- (id)faultForGlobalID: (EOGlobalID *)globalID + editingContext: (EOEditingContext *)context +{ + //OK + id object = [self objectForGlobalID: globalID]; + + if (!object) + { + BOOL isTemporary = [globalID isTemporary]; + + if (isTemporary) + { + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + } + else + { + object = [_objectStore faultForGlobalID: globalID + editingContext: self]; + } + } + + return object; +} + +- (id)faultForRawRow: (NSDictionary *)row + entityNamed: (NSString *)entityName + editingContext: (EOEditingContext *)context +{ + EOEntityClassDescription *classDesc; + EOGlobalID *globalID; + id object; + id objectCopy; + + classDesc = (id)[EOClassDescription classDescriptionForEntityName: + entityName]; + globalID = [[classDesc entity] globalIDForRow: row]; + object = [self objectForGlobalID: globalID]; + + if (object) + { + if (context == self) + return object; + + objectCopy = [classDesc createInstanceWithEditingContext: context + globalID: globalID + zone: NULL]; + + NSAssert1(objectCopy, @"No Object. classDesc=%@", classDesc); + [objectCopy updateFromSnapshot: [object snapshot]]; + + [context recordObject: objectCopy + globalID: globalID]; + + return objectCopy; + } + + object = [_objectStore faultForRawRow: row + entityNamed: entityName + editingContext: self]; + + return object; +} + +- (id)faultForRawRow: (id)row entityNamed: (NSString *)entityName +{ + id object; + + EOFLOGObjectFnStartOrCond(@"EOEditingContext"); + + object = [self faultForRawRow: row + entityNamed: entityName + editingContext: self]; + + EOFLOGObjectFnStopOrCond(@"EOEditingContext"); + + return object; +} + +- (NSArray *)arrayFaultWithSourceGlobalID: (EOGlobalID *)globalID + relationshipName: (NSString *)name + editingContext: (EOEditingContext *)context +{ + NSArray *fault; + id object = [self objectForGlobalID: globalID]; + id objectCopy; + + if (object) + { + if (context == self) + { + fault = [object valueForKey:name]; + if (fault) + return fault; + } + else + { + objectCopy = [[EOClassDescription classDescriptionForEntityName: + [globalID entityName]] + createInstanceWithEditingContext: context + globalID: globalID + zone: NULL]; + + NSAssert1(objectCopy, @"No Object. globalID=%@", globalID); + [objectCopy updateFromSnapshot: [object snapshot]]; + + [context recordObject: objectCopy + globalID: globalID]; + + return [objectCopy valueForKey: name]; + } + } + + return [_objectStore arrayFaultWithSourceGlobalID: globalID + relationshipName: name + editingContext: self]; +} + +- (void)initializeObject: (id)object + withGlobalID: (EOGlobalID *)globalID + editingContext: (EOEditingContext *)context +{ +//near OK + EOObjectStore *objectStore = nil; + + _flags.ignoreChangeNotification = YES; + + if (self == context) + { + objectStore = [(EOObjectStoreCoordinator*)_objectStore objectStoreForGlobalID: globalID]; + [objectStore initializeObject: object + withGlobalID: globalID + editingContext: context]; + } + else + { + NSEmitTODO(); + [self notImplemented: _cmd];//TODO + } + // [EOObserverCenter notifyObserversObjectWillChange: nil]; + _flags.ignoreChangeNotification = NO; +} + +- (NSArray *)objectsForSourceGlobalID: (EOGlobalID *)globalID + relationshipName: (NSString *)name + editingContext: (EOEditingContext *)context +{ + NSArray *objects = nil; + + if (self == context) + { + //TODOLOCK + [self lock]; + NS_DURING + { + objects = [_objectStore objectsForSourceGlobalID: globalID + relationshipName: name + editingContext: context]; + } + NS_HANDLER + { + NSLog(@"%@ (%@)", localException, [localException reason]); + NSDebugMLog(@"%@ (%@)", localException, [localException reason]); + [self unlock]; + [localException raise]; + } + NS_ENDHANDLER; + + [self unlock]; + } + else + { + NSEmitTODO(); + [self notImplemented: _cmd];//TODO + } + + return objects; +} + +- (void)refaultObject: object + withGlobalID: (EOGlobalID *)globalID + editingContext: (EOEditingContext *)context +{ + //Near OK + if (object) + { + //call globalID isTemporary //ret NO + if (self == context)//?? + { + //NO: in EODatabaseConetxt [object clearProperties]; + + //OK + [_objectStore refaultObject: object + withGlobalID: globalID + editingContext: context]; + //OK + [self clearOriginalSnapshotForObject: object]; + } + else + { + [self notImplemented: _cmd]; + } + } +} + +- (void)saveChangesInEditingContext: (EOEditingContext *)context +{ + if (context != self) + { + NSArray *objects; + NSEnumerator *objsEnum; + EOGlobalID *gid; + id object, localObject; + + objects = [context insertedObjects]; + + objsEnum = [objects objectEnumerator]; + while ((object = [objsEnum nextObject])) + { + gid = [context globalIDForObject: object]; + + localObject = [[EOClassDescription classDescriptionForEntityName: + [gid entityName]] + createInstanceWithEditingContext: context + globalID: gid + zone: NULL]; + + NSAssert1(localObject, @"No Object. gid=%@", gid); + + [localObject updateFromSnapshot: [object snapshot]]; + + [self recordObject: localObject + globalID: gid]; + } + + objects = [context updatedObjects]; + + objsEnum = [objects objectEnumerator]; + while ((object = [objsEnum nextObject])) + { + gid = [context globalIDForObject: object]; + localObject = [self objectForGlobalID: gid]; + + [localObject updateFromSnapshot:[object snapshot]]; + } + + objects = [context deletedObjects]; + + objsEnum = [objects objectEnumerator]; + while ((object = [objsEnum nextObject])) + { + gid = [context globalIDForObject: object]; + localObject = [self objectForGlobalID: gid]; + + [self deleteObject: localObject]; + } + } +} + +- (NSArray *)objectsWithFetchSpecification: (EOFetchSpecification *)fetch + editingContext: (EOEditingContext *)context +{ + //OK + NSArray *objects = nil; + + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOEditingContext", + @"_objectStore=%@ fetch=%@ context=%@", + _objectStore, fetch, context); + + [self lock]; //TODOLOCK + + NS_DURING + { + objects = [_objectStore objectsWithFetchSpecification: fetch + editingContext: context]; + } + NS_HANDLER + { + EOFLOGObjectLevelArgs(@"EOEditingContext", @"EXCEPTION: %@", + localException); + + [self unlock]; //TODOLOCK + + if ([self handleError: localException]) + { + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + } + else + { + NSEmitTODO(); + [self notImplemented: _cmd]; //TODO + } + } + NS_ENDHANDLER; + + [self unlock]; //TODOLOCK + + EOFLOGObjectFnStop(); + + return objects; +} + +- (void)lockObjectWithGlobalID: (EOGlobalID *)gid + editingContext: (EOEditingContext *)context +{ + [_objectStore lockObjectWithGlobalID: gid + editingContext: context]; +} + +- (BOOL)isObjectLockedWithGlobalID: (EOGlobalID *)gid + editingContext: (EOEditingContext *)context +{ + return [_objectStore isObjectLockedWithGlobalID: gid + editingContext: context]; +} + +@end + + +@implementation NSObject (EOEditingContext) + +- (EOEditingContext *)editingContext +{ + return [EOObserverCenter observerForObject: self + ofClass: [EOEditingContext class]]; +} + +@end + + +@implementation NSObject (EOEditors) + +/** Called by the EOEditingContext to determine if the editor is "dirty" **/ +- (BOOL)editorHasChangesForEditingContext: (EOEditingContext *)editingContext +{ + return NO; +} + +- (void)editingContextWillSaveChanges: (EOEditingContext *)editingContext +{ + return; +} + +@end + + +// +// EOMessageHandler informal protocol +// +@implementation NSObject (EOMessageHandlers) + +- (void)editingContext: (EOEditingContext *)editingContext + presentErrorMessage: (NSString *)message +{ + NSDebugMLog(@"error=%@", message); +} + +- (BOOL)editingContext: (EOEditingContext *)editingContext +shouldContinueFetchingWithCurrentObjectCount: (unsigned)count + originalLimit: (unsigned)limit + objectStore: (EOObjectStore *)objectStore +{ + return NO; +} + +@end + + +@implementation EOEditingContext (EORendezvous) + ++ (void)setSubstitutionEditingContext: (EOEditingContext *)ec +{ + [self notImplemented: _cmd]; //TODO +} + ++ (EOEditingContext *)substitutionEditingContext +{ + return [self notImplemented: _cmd]; //TODO +} + ++ (void)setDefaultParentObjectStore: (EOObjectStore *)store +{ + ASSIGN(defaultParentStore, store); +} + ++ (EOObjectStore *)defaultParentObjectStore +{ + return defaultParentStore; +} + +@end + +@implementation EOEditingContext (EOStateArchiving) + ++ (void)setUsesContextRelativeEncoding: (BOOL)yn +{ + [self notImplemented: _cmd]; //TODO +} + ++ (BOOL)usesContextRelativeEncoding +{ + [self notImplemented: _cmd]; //TODO + return NO; +} + ++ (void)encodeObject: (id)object + withCoder: (NSCoder *)coder +{ + [self notImplemented: _cmd]; //TODO +} + ++ (id)initObject: (id)object + withCoder: (NSCoder *)coder +{ + return [self notImplemented: _cmd]; //TODO +} + +@end + + +// Target action methods for InterfaceBuilder +// +@implementation EOEditingContext (EOTargetAction) + +- (void)saveChanges: (id)sender // TODO +{ + NS_DURING + [self saveChanges]; + NS_HANDLER + { + if(_messageHandler + && [_messageHandler + respondsTo: @selector(editingContext:presentErrorMessage:)] == YES) + [_messageHandler editingContext: self + presentErrorMessage: [localException reason]]; + } + NS_ENDHANDLER; +} + +- (void)refault: (id)sender +{ + [self refaultObjects]; +} + +- (void)revert: (id)sender +{ + [self revert]; +} + +- (void)refetch: (id)sender +{ + [self invalidateAllObjects]; +} + +- (void)undo: (id)sender +{ + [_undoManager undo]; +} + +- (void)redo: (id)sender +{ + [_undoManager redo]; +} + +- (NSString*)unprocessedDescription +{ + NSString *desc; + + EOFLOGObjectFnStart(); + + desc = [NSString stringWithFormat: @"<%p:\nunprocessedChanges [nb:%d]=%p %@\n\nunprocessedDeletes [nb:%d]=%p %@\n\nunprocessedInserts[nb:%d]=%p %@>\n", + self, + NSCountHashTable(_unprocessedChanges), + _unprocessedChanges, + NSStringFromHashTable(_unprocessedChanges), + NSCountHashTable(_unprocessedDeletes), + _unprocessedDeletes, + NSStringFromHashTable(_unprocessedDeletes), + NSCountHashTable(_unprocessedInserts), + _unprocessedInserts, + NSStringFromHashTable(_unprocessedInserts)]; + + EOFLOGObjectFnStop(); + + return desc; +} + +- (NSString*)objectsDescription +{ + NSString *desc; + + EOFLOGObjectFnStart(); + + desc = [NSString stringWithFormat: @"<%p:\nchangedObjects [nb:%d]=%p %@\n\ndeletedObjects [nb:%d]=%p %@\n\ninsertedObjects [nb:%d]=%p %@>\n", + self, + NSCountHashTable(_changedObjects), + _changedObjects, + NSStringFromHashTable(_changedObjects), + NSCountHashTable(_deletedObjects), + _deletedObjects, + NSStringFromHashTable(_deletedObjects), + NSCountHashTable(_insertedObjects), + _insertedObjects, + NSStringFromHashTable(_insertedObjects)]; + + EOFLOGObjectFnStop(); + + return desc; +} + +@end + + +// To support multithreaded operation +@implementation EOEditingContext(EOMultiThreaded) + ++ (void)setEOFMultiThreadedEnabled: (BOOL)flag +{ + [self notImplemented: _cmd]; +} + +- (BOOL)tryLock +{ + BOOL tryLock = NO; + + EOFLOGObjectFnStart(); + + tryLock = [_lock tryLock]; + + if (tryLock) + _lockCount++; + + EOFLOGObjectFnStop(); + + return tryLock; +} + +- (void)lock +{ + EOFLOGObjectFnStart(); + + [_lock lock]; + _lockCount++; + + EOFLOGObjectFnStop(); +} + +- (void)unlock +{ + EOFLOGObjectFnStart(); + + _lockCount--; + [_lock unlock]; + + EOFLOGObjectFnStop(); +} + +- (void) _assertSafeMultiThreadedAccess: (SEL)param0 +{ + [self notImplemented: _cmd]; //TODO +} + +@end + +// Informations +@implementation EOEditingContext(EOEditingContextInfo) + +- (NSDictionary*)unprocessedInfo +{ + NSDictionary *infoDict = nil; + NSHashTable *hashTables[3] = { _unprocessedChanges, + _unprocessedDeletes, + _unprocessedInserts }; + NSMutableArray *objectsForInfo[3] = { [NSMutableArray array], //inserted + [NSMutableArray array], //deleted + [NSMutableArray array] }; //updated + id object; + int which; + + EOFLOGObjectFnStart(); + + for (which = 0; which < 3; which++) + { + NSHashEnumerator hashEnumerator = NSEnumerateHashTable(hashTables[which]); + + while ((object = (id)NSNextHashEnumeratorItem(&hashEnumerator))) + { + NSString *info = [NSString stringWithFormat: @"%@ (%p)", + [[object entity] name], + object]; + + [objectsForInfo[which] addObject: info]; + } + } + + infoDict = [NSDictionary dictionaryWithObjectsAndKeys: + objectsForInfo[0], @"insert", + objectsForInfo[1], @"delete", + objectsForInfo[2], @"update", + nil, nil]; + + NSDebugMLog(@"infoDict=%@", infoDict); + EOFLOGObjectFnStop(); + + return infoDict; +} + +- (NSDictionary*)pendingInfo +{ + NSDictionary *infoDict = nil; + NSHashTable *hashTables[3] = { _insertedObjects, + _deletedObjects, + _changedObjects }; + NSMutableArray *objectsForInfo[3] = { [NSMutableArray array], //inserted + [NSMutableArray array], //deleted + [NSMutableArray array] }; //updated + id object; + int which; + + EOFLOGObjectFnStart(); + + for (which = 0; which < 3; which++) + { + NSHashEnumerator hashEnumerator = NSEnumerateHashTable(hashTables[which]); + + while ((object = (id)NSNextHashEnumeratorItem(&hashEnumerator))) + { + NSString *info = [NSString stringWithFormat: @"%@ (%p)", + [[object entity] name], + object]; + + [objectsForInfo[which] addObject: info]; + } + } + + infoDict = [NSDictionary dictionaryWithObjectsAndKeys: + objectsForInfo[0], @"inserted", + objectsForInfo[1], @"deleted", + objectsForInfo[2], @"updated", + nil, nil]; + + NSDebugMLog(@"infoDict=%@", infoDict); + EOFLOGObjectFnStop(); + + return infoDict; +} + +@end diff --git a/EOControl/EOFault.h b/EOControl/EOFault.h new file mode 100644 index 0000000..6051520 --- /dev/null +++ b/EOControl/EOFault.h @@ -0,0 +1,182 @@ +/* + EOFault.h + + Copyright (C) 1996-2000 Free Software Foundation, Inc. + + Author: Mircea Oancea + Date: 1996 + + Author: Mirko Viviani + Date: June 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOFault_h__ +#define __EOFault_h__ + +#include + +@class EOFaultHandler; + +/* + * EOFault class + */ + + +@interface EOFault +{ + Class isa; + EOFaultHandler *_handler; +} + + ++ (void)initialize; ++ (Class)superclass; ++ (Class)class; ++ (id)self; + ++ (id)retain; ++ (void)release; ++ (id)autorelease; ++ (unsigned)retainCount; + ++ (BOOL)isKindOfClass: (Class)aClass; ++ (void)doesNotRecognizeSelector: (SEL)sel; ++ (BOOL)respondsToSelector: (SEL)sel; + + ++ (void)makeObjectIntoFault: (id)object withHandler: (EOFaultHandler *)handler; + ++ (BOOL)isFault: (id)object; + ++ (void)clearFault: (id)fault; + ++ (EOFaultHandler *)handlerForFault: (id)fault; + ++ (Class)targetClassForFault: (id)fault; + + +- (Class)superclass; +- (Class)class; + +- (BOOL)isKindOfClass: (Class)aclass; +- (BOOL)isMemberOfClass: (Class)aclass; +- (BOOL)conformsToProtocol: (Protocol *)protocol; +- (BOOL)respondsToSelector: (SEL)sel; +- (NSMethodSignature *)methodSignatureForSelector: (SEL)aSelector; + +- (id)retain; +- (void)release; +- (id)autorelease; +- (unsigned)retainCount; + +- (NSString *)description; +- (NSString *)descriptionWithIndent: (unsigned)level; +- (NSString *)descriptionWithLocale: (NSDictionary *)locale; +- (NSString *)descriptionWithLocale: (NSDictionary *)locale + indent: (unsigned)level; +- (NSString *)eoDescription; +- (NSString *)eoShallowDescription; + +- (void)dealloc; + +- (NSZone *)zone; +- (BOOL)isProxy; // Always NO. + +- (id)self; + + +- (void)doesNotRecognizeSelector: (SEL)sel; +- (void)forwardInvocation: (NSInvocation *)invocation; + +- gcSetNextObject: (id)anObject; +- gcSetPreviousObject: (id)anObject; +- (id)gcNextObject; +- (id)gcPreviousObject; +- (BOOL)gcAlreadyVisited; +- (void)gcSetVisited: (BOOL)flag; +- (void)gcDecrementRefCountOfContainedObjects; +- (BOOL)gcIncrementRefCountOfContainedObjects; +- (BOOL)isGarbageCollectable; +- (void)gcIncrementRefCount; +- (void)gcDecrementRefCount; + +@end /* EOFault */ + + +@interface EOFaultHandler : NSObject +{ + Class _targetClass; // the first 8 bytes of + void *_extraData; // the faulted object + + unsigned _extraRefCount; + + BOOL gcEnabled; + id gcNextObject; + id gcPreviousObject; + struct { + unsigned gcVisited:1; + unsigned refCount:31; + } gcFlags; +@public + int gcCountainedObjectRefCount; +} + +- (void)setTargetClass: (Class)target extraData: (void *)data; +- (Class)targetClass; +- (void *)extraData; + +- (void)incrementExtraRefCount; +- (BOOL)decrementExtraRefCountWasZero; +- (unsigned)extraRefCount; + +- (NSString *)descriptionForObject: object; + +- (Class)classForFault: (id)fault; + +- (BOOL)isKindOfClass: (Class)aclass forFault: (id)fault; +- (BOOL)isMemberOfClass: (Class)aclass forFault: (id)fault; +- (BOOL)conformsToProtocol: (Protocol *)protocol forFault: (id)fault; +- (BOOL)respondsToSelector: (SEL)sel forFault: (id)fault; +- (NSMethodSignature *)methodSignatureForSelector: (SEL)selector + forFault: (id)fault; + +- (void)completeInitializationOfObject: (id)object; + +- (BOOL)shouldPerformInvocation: (NSInvocation *)invocation; + +- (void)faultWillFire: (id)object; + +// Garbage Collector + +- gcSetNextObject: (id)anObject; +- gcSetPreviousObject: (id)anObject; +- (id)gcNextObject; +- (id)gcPreviousObject; +- (BOOL)gcAlreadyVisited; +- (void)gcSetVisited: (BOOL)flag; +- (void)gcDecrementRefCountOfContainedObjects; +- (BOOL)gcIncrementRefCountOfContainedObjects; +- (BOOL)isGarbageCollectable; +- (void)gcIncrementRefCount; +- (void)gcDecrementRefCount; + +@end + +#endif /* __EOFault_h__ */ diff --git a/EOControl/EOFault.m b/EOControl/EOFault.m new file mode 100644 index 0000000..fe05671 --- /dev/null +++ b/EOControl/EOFault.m @@ -0,0 +1,590 @@ +/** + EOFault.m EOFault Class + + Copyright (C) 1996-2002 Free Software Foundation, Inc. + + Author: Mircea Oancea + Date: 1996 + + Author: Mirko Viviani + Date: June 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#include +#include + +#import +#import +#import +#import +#import +#import +#import + +#import +#import +#import + +#import +#import + +#import + + +typedef struct { + Class isa; +} *my_objc_object; + +#define object_is_instance(object) \ + ((object != nil) && CLS_ISCLASS(((my_objc_object)object)->isa)) + + +/* + * EOFault class + */ + +@implementation EOFault + ++ (void)initialize +{ + // Must be here as initialize is called for each root class + // without asking if it responds to it ! +} + ++ (Class)superclass +{ + return class_get_super_class(self); +} + ++ (Class)class +{ + return self; +} + ++ self +{ + return self; +} + ++ (id)retain +{ + return self; +} + ++ (void)release +{ + return; +} + ++ (id)autorelease +{ + return self; +} + ++ (unsigned)retainCount +{ + return UINT_MAX; +} + ++ (BOOL)isKindOfClass: (Class)aClass +{ + if(aClass == [EOFault class]) + return YES; + + return NO; +} + ++ (void)doesNotRecognizeSelector: (SEL)sel +{ + return; + [self notImplemented: _cmd]; +} + ++ (BOOL)respondsToSelector: (SEL)sel +{ + return (IMP)class_get_instance_method(self, sel) != (IMP)0; +} + + +// Fault class methods + ++ (void)makeObjectIntoFault: (id)object + withHandler: (EOFaultHandler *)handler +{ + if (object) + { + EOFault *fault = object; + unsigned int refs; + + NSAssert(handler,@"No Handler"); + + refs = [object retainCount]; + + [handler setTargetClass: [object class] + extraData: fault->_handler]; + fault->isa = self; + fault->_handler = [handler retain]; + + while (refs-- > 0) + [fault retain]; + } +} + ++ (BOOL)isFault: (id)object +{ +// NSDebugFLLog(@"gsdb",@"object=%p",object); + + if (object == nil) + return NO; + else + return ((EOFault *)object)->isa == self; +} + ++ (void)clearFault: (id)fault +{ + EOFaultHandler *handler; + EOFault *aFault = (EOFault *)fault; + BOOL gcEnabled = NO; + unsigned gcCountainedObjectRefCount = 0; + int refs = 0; + + NSDebugFLLog(@"gsdb", @"START fault=%p", fault); + + if ([EOFault isFault:fault] == NO) + { +//REVOIR!!! +/* + [NSException raise:NSInvalidArgumentException + format:@"%@ -- %@ 0x%x: object %@ of class %@ is not a fault object", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + fault, + [fault class]]; +*/ + } + else + { + handler = aFault->_handler; + + [handler faultWillFire: fault]; + + refs = [handler extraRefCount]; + gcEnabled = [handler isGarbageCollectable]; + gcCountainedObjectRefCount = aFault->_handler->gcCountainedObjectRefCount; + + aFault->isa = [handler targetClass]; + aFault->_handler = [handler extraData]; + + [handler autorelease]; + + refs -= [fault retainCount]; + + if (refs > 0) + while (refs-- > 0) + [aFault retain]; + else + while (refs++ < 0) + [aFault release]; + + if(gcEnabled) + { + [aFault gcIncrementRefCount]; + [aFault gcSetNextObject: [self gcNextObject]]; + [aFault gcSetPreviousObject: [self gcPreviousObject]]; + + while (gcCountainedObjectRefCount-- > 0) + [aFault gcIncrementRefCountOfContainedObjects]; + } + } + + NSDebugFLLog(@"gsdb", @"STOP fault=%p", fault); +} + ++ (EOFaultHandler *)handlerForFault:(id)fault +{ + BOOL isFault = [EOFault isFault: fault]; + + NSDebugFLLog(@"gsdb", @"object %p is%s a fault", fault, (isFault ? "" : " not")); + + if (isFault) + return ((EOFault *)fault)->_handler; + else + return nil; +} + ++ (Class)targetClassForFault: (id)fault +{ + if ([EOFault isFault:fault]) + return [((EOFault *)fault)->_handler targetClass]; + else + return nil; +} + + +// Fault Instance methods + +- superclass +{ + return [[_handler targetClass] superclass]; +} + +- (Class)class +{ + return [_handler targetClass]; +} + +- (BOOL)isKindOfClass: (Class)aclass; +{ + Class class; + BOOL koc=NO; + + class = [_handler targetClass]; + + for (; !koc && class != Nil; class = class_get_super_class(class)) + if (class == aclass) + koc = YES; + + return koc; +} + +- (BOOL)isMemberOfClass: (Class)aclass +{ + return [_handler targetClass] == aclass; +} + +- (BOOL)conformsToProtocol: (Protocol *)protocol +{ + int i; + struct objc_protocol_list* protos; + Class class, sClass; + + class = [_handler targetClass]; + + for (protos = class->protocols; protos; protos = protos->next) + { + for (i = 0; i < protos->count; i++) + if ([protos->list[i] conformsTo: protocol]) + return YES; + } + + sClass = [class superclass]; + + if (sClass) + return [sClass conformsToProtocol: protocol]; + else + return NO; +} + +- (BOOL)respondsToSelector: (SEL)aSelector +{ + Class class; + BOOL respondsToSelector; + + NSDebugFLLog(@"gsdb", @"START self=%p", self); + + class = [_handler targetClass]; + NSDebugFLLog(@"gsdb", @"class=%@ aSelector=%s", class, sel_get_name(aSelector)); + + respondsToSelector = ((IMP)class_get_instance_method(class, aSelector) + != (IMP)0); + NSDebugFLLog(@"gsdb", @"STOP self=%p", self); + + return respondsToSelector; +} + +- (NSMethodSignature *)methodSignatureForSelector: (SEL)aSelector +{ + NSMethodSignature *sig; + + NSDebugFLLog(@"gsdb", @"START self=%p", self); + NSDebugFLLog(@"gsdb", @"_handler=%p", _handler); + + sig = [_handler methodSignatureForSelector: aSelector + forFault: self]; + + NSDebugFLLog(@"gsdb", @"STOP self=%p", self); + + return sig; +} + +- retain +{ + [_handler incrementExtraRefCount]; + + return self; +} + +- (void)release +{ + if ([_handler extraRefCount] <= 0) + [self dealloc]; + else + [_handler decrementExtraRefCountWasZero]; +} + +- autorelease +{ + [NSAutoreleasePool addObject: self]; + + return self; +} + +- (unsigned)retainCount +{ + return [_handler extraRefCount]; +} + +- (NSString *)description +{ + return [_handler descriptionForObject: self]; +} + +- (NSString *)descriptionWithIndent: (unsigned)level +{ + return [self description]; +} + +- (NSString *)descriptionWithLocale: (NSDictionary *)locale +{ + //OK + return [self description]; +} + +- (NSString *)descriptionWithLocale: (NSDictionary *)locale + indent: (unsigned)level +{ + return [self description]; +} + +- (NSString *)descriptionWithLocale: (NSDictionary *)locale + indent: (unsigned)level + to: (id)output; +{ + return [self description]; +} + +- (NSString *)eoDescription +{ + return [self description]; +} + +- (NSString *)eoShallowDescription +{ + return [self description]; +} + +- (EOKeyGlobalID *)globalID +{ + if ([_handler respondsToSelector: @selector(globalID)]) + return [(id)_handler globalID]; + else + { + [_handler completeInitializationOfObject: self]; + return [self globalID]; + } +} + +- (EODatabaseContext *)databaseContext +{ + if ([_handler respondsToSelector: @selector(databaseContext)]) + return [(id)_handler databaseContext]; + else + { + [_handler completeInitializationOfObject: self]; + return [self databaseContext]; + } +} + +- (EOEditingContext *)editingContext +{ + if ([_handler respondsToSelector: @selector(editingContext)]) + return [_handler editingContext]; + else + { + [_handler completeInitializationOfObject: self]; + + return [self editingContext]; + } +} + +/* +- (EOKeyGlobalID *)sourceGlobalID; +- (NSString *)relationshipName; +*/ + +- (void)dealloc +{ + [EOFault clearFault: self]; + [self dealloc]; +} + +- (NSZone *)zone +{ + return NSZoneFromPointer(self); +} + +- (BOOL)isProxy +{ + return NO; +} + +- (id)self +{ + [_handler completeInitializationOfObject: self]; + + return self; +} + +- (void)doesNotRecognizeSelector: (SEL)sel +{ + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: selector \"%@\" not recognized", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + NSStringFromSelector(sel)]; +} + +- (retval_t)forward: (SEL)sel + : (arglist_t)args +{ + retval_t ret; + NSInvocation *inv; + + NSDebugFLLog(@"gsdb", @"START self=%p", self); + + inv = [[[NSInvocation alloc] initWithArgframe: args + selector: sel] + autorelease]; + [self forwardInvocation: inv]; + + ret = [inv returnFrame: args]; + NSDebugFLLog(@"gsdb", @"STOP self=%p", self); + + return ret; +} + +- (void)forwardInvocation: (NSInvocation *)invocation +{ + NSDebugFLLog(@"gsdb", @"START self=%p", self); + + if ([_handler shouldPerformInvocation: invocation]) + [_handler completeInitializationOfObject: self]; + + [invocation invoke]; + + NSDebugFLLog(@"gsdb", @"STOP self=%p", self); +} + +- (unsigned int)hash +{ + unsigned int hash; + EOFaultHandler *handler; + Class fault; + + fault = isa; + handler = _handler; + + isa = [handler targetClass]; + _handler = [handler extraData]; + + hash = [self hash]; + + isa = fault; + _handler = handler; + + return hash; +} + +// GC + +- gcSetNextObject: (id)anObject +{ + return [_handler gcSetNextObject: anObject]; +} + +- gcSetPreviousObject: (id)anObject +{ + return [_handler gcSetPreviousObject: anObject]; +} + +- (id)gcNextObject +{ + return [_handler gcNextObject]; +} + +- (id)gcPreviousObject +{ + return [_handler gcPreviousObject]; +} + +- (BOOL)gcAlreadyVisited +{ + return [_handler gcAlreadyVisited]; +} + +- (void)gcSetVisited: (BOOL)flag +{ + [_handler gcSetVisited: flag]; +} + +- (void)gcDecrementRefCountOfContainedObjects +{ + [_handler gcDecrementRefCountOfContainedObjects]; +} + +- (BOOL)gcIncrementRefCountOfContainedObjects +{ + return [_handler gcIncrementRefCountOfContainedObjects]; +} + +- (BOOL)isGarbageCollectable +{ + return [_handler isGarbageCollectable]; +} + +- (void)gcIncrementRefCount +{ + [_handler gcIncrementRefCount]; +} + +- (void)gcDecrementRefCount +{ + NSDebugFLLog(@"gsdb", @"START self=%p", self); + + NSDebugFLLog(@"gsdb", @"handler gcDecrementRefCount"); + + [_handler gcDecrementRefCount]; + + NSDebugFLLog(@"gsdb", @"STOP self=%p", self); +} + +@end + diff --git a/EOControl/EOFaultHandler.m b/EOControl/EOFaultHandler.m new file mode 100644 index 0000000..042b9ed --- /dev/null +++ b/EOControl/EOFaultHandler.m @@ -0,0 +1,374 @@ +/** + EOFaultHandler.m EOFaultHandler Class + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: June 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import +#import +#import +#import +#import + +#import +#import +#import +#import +#import + + +BOOL __isGCEnabled(Class class_) +{ + Class gcObjectClass = [GCObject class]; + + if ([class_ conformsToProtocol: @protocol(GarbageCollecting)]) + return YES; + else if ([class_ instancesRespondToSelector: @selector(gcIncrementRefCount)]) + return YES; + else + { + Class class; + + for (class = class_; + class != Nil; + class = class_get_super_class (class)) + { + if (class == gcObjectClass) + return YES; + else if ([class instancesRespondToSelector: @selector(gcIncrementRefCount)]) + return YES; + else if ([class instancesRespondToSelector: @selector(gcNextObject)]) + return YES; + else if ([class conformsToProtocol: @protocol(GarbageCollecting )]) + return YES; + } + } + + return NO; +} + + +@implementation EOFaultHandler + +- (id)init +{ + if ((self = [super init])) + { + } + + return self; +} + +- (void)setTargetClass: (Class)target + extraData: (void *)data +{ + _targetClass = target; + _extraData = data; + + gcEnabled = __isGCEnabled(_targetClass); + + if (gcEnabled) + _extraRefCount++; +} + +- (Class)targetClass +{ + return _targetClass; +} + +- (void *)extraData +{ + return _extraData; +} + +- (void)incrementExtraRefCount +{ + _extraRefCount++; +} + +- (BOOL)decrementExtraRefCountWasZero +{ + if (!(--_extraRefCount)) + return YES; + + return NO; +} + +- (unsigned)extraRefCount +{ + return _extraRefCount; +} + +- (NSString *)descriptionForObject: object +{ + return [NSString stringWithFormat: @"%@ (EOFault 0x%08x)", + NSStringFromClass(_targetClass), object]; +} + +- (Class)classForFault: (id)fault +{ + return [self targetClass]; +} + +- (BOOL)isKindOfClass: (Class)aclass + forFault: (id)fault +{ + Class class; + + for (class = _targetClass; class != Nil; class = class_get_super_class(class)) + { + if (class == aclass) + return YES; + } + + return NO; +} + +- (BOOL)isMemberOfClass: (Class)aclass + forFault: (id)fault +{ + return _targetClass == aclass; +} + +- (BOOL)conformsToProtocol: (Protocol *)protocol + forFault: (id)fault +{ + int i; + struct objc_protocol_list *proto_list; + Class class; + + for(class = _targetClass; class != Nil; class = class_get_super_class(class)) + { + for (proto_list = + ((struct objc_class *)_targetClass)->class_pointer->protocols; + proto_list; proto_list = proto_list->next) + { + for (i = 0; i < proto_list->count; i++) + { + if ([proto_list->list[i] conformsTo: protocol]) + return YES; + } + } + } + + return NO; +} + +- (BOOL)respondsToSelector: (SEL)sel + forFault: (id)fault +{ + [self notImplemented: _cmd]; + return NO; + // return __objc_responds_to((id)&self, sel); +} + +- (NSMethodSignature *)methodSignatureForSelector: (SEL)selector + forFault: (id)fault +{ // TODO + NSMethodSignature *sig; + + EOFLOGObjectFnStart(); + + NSDebugMLLog(@"gsdb", @"_targetClass=%p", _targetClass); + NSDebugMLLog(@"gsdb", @"_targetClass=%@", _targetClass); + NSDebugMLLog(@"gsdb", @"selector=%@", NSStringFromSelector(selector)); + //TODO VERIFY + NSAssert(_targetClass, @"No target class"); + + sig = [_targetClass instanceMethodSignatureForSelector: selector]; + + NSDebugMLLog(@"gsdb",@"sig=%p", (void*)sig); + EOFLOGObjectFnStop(); + + return sig; +} + +- (void)completeInitializationOfObject: (id)object +{ + [self subclassResponsibility: _cmd]; +} + +- (BOOL)shouldPerformInvocation: (NSInvocation *)invocation +{ + return YES; +} + +- (void)faultWillFire: (id)object +{ + return; +} + +// GC + ++ allocWithZone: (NSZone *)zone_ +{ + id newObject = [super allocWithZone: zone_]; + + ((EOFaultHandler *)newObject)->gcFlags.refCount = 0; + + return newObject; +} + +/* +- retain +{ + if (gcEnabled) + { + gcFlags.refCount++; + return self; + } + else + { + return [super retain]; + }; +} + +- (unsigned int)retainCount +{ + if (gcEnabled) + { + return gcFlags.refCount; + } + else + { + return [super retainCount]; + }; +} +*/ +- gcSetNextObject: (id)anObject +{ + if (gcEnabled) + gcNextObject = anObject; + + return self; +} + +- gcSetPreviousObject: (id)anObject +{ + if (gcEnabled) + gcPreviousObject = anObject; + + return self; +} + +- (id)gcNextObject +{ + if (gcEnabled) + return gcNextObject; + + return nil; +} + +- (id)gcPreviousObject +{ + if (gcEnabled) + return gcPreviousObject; + + return nil; +} + +- (BOOL)gcAlreadyVisited +{ + if (gcEnabled) + return gcFlags.gcVisited; + + return YES; +} + +- (void)gcSetVisited: (BOOL)flag +{ + if (gcEnabled) + gcFlags.gcVisited = flag; +} + +- (void)gcDecrementRefCountOfContainedObjects +{ + EOFLOGObjectFnStart(); + + if (gcEnabled) + gcCountainedObjectRefCount--; + + EOFLOGObjectFnStop(); +} + +- (BOOL)gcIncrementRefCountOfContainedObjects +{ + if (gcEnabled) + { + if (gcFlags.gcVisited) + return NO; + + gcCountainedObjectRefCount++; + gcFlags.gcVisited = YES; + + return YES; + } + + return NO; +} + +- (BOOL)isGarbageCollectable +{ + return gcEnabled; +} + +- (void)gcIncrementRefCount +{ + if (gcEnabled); + //gcFlags.refCount++; + // faultReferences++; +} + +- (void)gcDecrementRefCount +{ + if(gcEnabled); + //gcFlags.refCount--; + // faultReferences--; +} + +/* +- (BOOL)afterFault +{ + if (gcEnabled) + { + [fault gcIncrementRefCount]; + [fault gcSetNextObject:[self gcNextObject]]; + [fault gcSetPreviousObject:[self gcPreviousObject]]; + while(gcCountainedObjectRefCount-- > 0) + [fault gcIncrementRefCountOfContainedObjects]; + }; + return NO; +} +*/ + +@end diff --git a/EOControl/EOFetchSpecification.h b/EOControl/EOFetchSpecification.h new file mode 100644 index 0000000..4eed871 --- /dev/null +++ b/EOControl/EOFetchSpecification.h @@ -0,0 +1,146 @@ +/* + EOFetchSpecification.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOFetchSpecification_h__ +#define __EOFetchSpecification_h__ + +#import + + +@class EOQualifier; +@class EOKeyValueArchiver; +@class EOKeyValueUnarchiver; + +@interface EOFetchSpecification : NSObject +{ + EOQualifier *_qualifier; + NSArray *_sortOrderings; + NSString *_entityName; + NSDictionary *_hints; + unsigned int _fetchLimit; + NSArray *_prefetchingRelationshipKeys; + NSArray *_rawAttributeKeys; + struct { + unsigned usesDistinct:1; + unsigned isDeep:1; + unsigned locksObjects:1; + unsigned refreshesRefetchedObjects:1; + unsigned promptsAfterFetchLimit:1; + unsigned allVariablesRequiredFromBindings:1; + unsigned :26; //padding + }_flags; +} + ++ (EOFetchSpecification *)fetchSpecification; + +- init; + +- initWithEntityName: (NSString *)entityName + qualifier: (EOQualifier *)qualifier + sortOrderings: (NSArray *)sortOrderings + usesDistinct: (BOOL)usesDistinct + isDeep: (BOOL)isDeep + hints: (NSDictionary *)hints; + +- (EOFetchSpecification *)fetchSpecificationByApplyingBindings: (id)bindings; + +- (EOFetchSpecification *)fetchSpecificationWithQualifierBindings: (NSDictionary *)bindings; + ++ (EOFetchSpecification *)fetchSpecificationNamed: (NSString *)name + entityNamed: (NSString *)entityName; + ++ (EOFetchSpecification *)fetchSpecificationWithEntityName: (NSString *)name + qualifier: (EOQualifier *)qualifier + sortOrderings: (NSArray *)sortOrderings; + + +- copyWithZone:(NSZone *)zone; + +- (id) initWithKeyValueUnarchiver: (EOKeyValueUnarchiver*)unarchiver; +- (void) encodeWithKeyValueArchiver: (EOKeyValueUnarchiver*)archiver; + +- (void)setEntityName: (NSString *)entityName; +- (NSString *)entityName; + +- (void)setSortOrderings: (NSArray *)sortOrderings; +- (NSArray *)sortOrderings; + +- (void)setQualifier: (EOQualifier *)qualifier; +- (EOQualifier *)qualifier; + +- (void)setUsesDistinct: (BOOL)usesDistinct; +- (BOOL)usesDistinct; + +- (void)setIsDeep: (BOOL)isDeep; +- (BOOL)isDeep; + +- (void)setLocksObjects: (BOOL)setLocksObjects; +- (BOOL)locksObjects; + +- (void)setRefreshesRefetchedObjects: (BOOL)refreshesRefetchedObjects; +- (BOOL)refreshesRefetchedObjects; + +- (void)setFetchLimit: (unsigned)fetchLimit; +- (unsigned)fetchLimit; + +- (void)setPromptsAfterFetchLimit: (BOOL)promptsAfterFetchLimit; +- (BOOL)promptsAfterFetchLimit; + +- (void)setAllVariablesRequiredFromBindings: (BOOL)allVariablesRequired; +- (BOOL)allVariablesRequiredFromBindings; + +- (void)setPrefetchingRelationshipKeyPaths: (NSArray *)prefetchingRelationshipKeys; +- (NSArray *)prefetchingRelationshipKeyPaths; + +- (void)setRawAttributeKeys: (NSArray *)rawAttributeKeys; +- (NSArray *)rawAttributeKeys; + +- (void)setFetchesRawRows: (BOOL)fetchRawRows; +- (BOOL)fetchesRawRows; + +- (void)setHints: (NSDictionary *)hints; +- (NSDictionary *)hints; +- (NSDictionary *)_hints; + +- (NSArray *)rawRowKeyPaths; +- (void)setRawRowKeyPaths: (NSArray *)rawRowKeyPaths; + +- (BOOL)requiresAllQualifierBindingVariables; +- (void)setRequiresAllQualifierBindingVariables: (BOOL)flag; + +@end + + + +extern NSString *EOPrefetchingRelationshipHintKey; + +extern NSString *EOFetchLimitHintKey; + +extern NSString *EOPromptsAfterFetchLimitHintKey; + + +#endif + diff --git a/EOControl/EOFetchSpecification.m b/EOControl/EOFetchSpecification.m new file mode 100644 index 0000000..7f07947 --- /dev/null +++ b/EOControl/EOFetchSpecification.m @@ -0,0 +1,497 @@ +/** + EOFetchSpecification.m EOFetchSpecification + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import +#import +#import +#import + +#import + + +@implementation EOFetchSpecification + ++ (EOFetchSpecification *)fetchSpecification +{ + return [[[self alloc] init] autorelease]; +} + +- (id) init +{ + if ((self = [super init])) + { + _flags.isDeep = YES; + } + + return self; +} + +// Turbocat +- (void)dealloc +{ +#ifdef DEBUG + NSString *fmt = GSDebugMethodMsg(self, _cmd, __FILE__, __LINE__, @"FNSTOP"); + EOFLOGObjectFnStartOrCond(@"EOFetchSpecification"); +#endif + + DESTROY(_qualifier); + DESTROY(_sortOrderings); + DESTROY(_entityName); + DESTROY(_hints); + DESTROY(_prefetchingRelationshipKeys); + DESTROY(_rawAttributeKeys); + + [super dealloc]; + +#ifdef DEBUG + EOFLOGObjectFnStopOrCondPlain(@"EOFetchSpecification", fmt); +#endif +} + +- (id) initWithEntityName: (NSString *)entityName + qualifier: (EOQualifier *)qualifier + sortOrderings: (NSArray *)sortOrderings + usesDistinct: (BOOL)usesDistinct + isDeep: (BOOL)isDeep + hints: (NSDictionary *)hints +{ + if ((self = [self init])) + { + ASSIGN(_entityName, entityName); + ASSIGN(_qualifier, qualifier); + ASSIGN(_sortOrderings, sortOrderings); + + [self setUsesDistinct: usesDistinct]; + [self setIsDeep: isDeep]; + [self setHints: hints]; + } + + return self; +} + +- (EOFetchSpecification *)fetchSpecificationByApplyingBindings: (id)bindings +{ + [self notImplemented:_cmd]; + return nil; +} + +- (EOFetchSpecification *)fetchSpecificationWithQualifierBindings: (NSDictionary *)bindings +{ + [self notImplemented: _cmd]; + return nil; +} + ++ (EOFetchSpecification *)fetchSpecificationNamed: (NSString *)name + entityNamed: (NSString *)entityName +{ + EOFetchSpecification *newEOFetchSpecification = nil; + EOModelGroup *anModelGroup; + + EOFLOGClassFnStartOrCond(@"EOFetchSpecification"); + + anModelGroup = [EOModelGroup defaultGroup]; + + if (anModelGroup) + newEOFetchSpecification = [anModelGroup fetchSpecificationNamed: name + entityNamed: entityName]; + + EOFLOGObjectFnStopOrCond(@"EOFetchSpecification"); + + return newEOFetchSpecification; +} + ++ (EOFetchSpecification *)fetchSpecificationWithEntityName: (NSString *)name + qualifier: (EOQualifier *)qualifier + sortOrderings: (NSArray *)sortOrderings +{ + return [[[EOFetchSpecification alloc] + initWithEntityName: name + qualifier: qualifier + sortOrderings: sortOrderings + usesDistinct: NO + isDeep: YES + hints: nil] autorelease]; +} + + +- (id) copyWithZone: (NSZone *)zone +{ + EOFetchSpecification *ret = [EOFetchSpecification allocWithZone:zone]; +//order: hints, isdeep, usesDistinct,sortOrderings, qualifier,entityName +//and call nitWithEntityName:qualifier:sortOrderings:usesDistinct:isDeep:hints: +//after: +/* [fetch setLocksObjects:[_fetchSpecification locksObjects]]; + [fetch setRefreshesRefetchedObjects:[_fetchSpecification refreshesRefetchedObjects]]; + [fetch setPrefetchingRelationshipKeyPaths:[_fetchSpecification prefetchingRelationshipKeyPaths + [fetch setRawRowKeyPaths:[_fetchSpecification rawRowKeyPaths +setFetchLimit:fetchLimit +setPromptsAfterFetchLimit: promptsAfterFetchLimit +setRequiresAllQualifierBindingVariables:requiresAllQualifierBindingVariables +*/ + //call setXX fn instead to have "willChange" ?? + ret->_qualifier = [()_qualifier copyWithZone: zone]; + ret->_sortOrderings = [_sortOrderings copyWithZone: zone]; //mirko: ASSIGN(ret->_sortOrderings, _sortOrderings); + ret->_entityName = [_entityName copyWithZone: zone]; + ret->_hints = [_hints copyWithZone: zone]; + ret->_prefetchingRelationshipKeys = [_prefetchingRelationshipKeys copyWithZone: zone]; + ret->_rawAttributeKeys = [_rawAttributeKeys copyWithZone: zone]; + ret->_fetchLimit = _fetchLimit; + ret->_flags = _flags; + + return ret; +} + +- (void)encodeWithCoder: (NSCoder *)coder +{ + [coder encodeObject: _qualifier]; + [coder encodeObject: _sortOrderings]; + [coder encodeObject: _entityName]; + [coder encodeObject: _hints]; + [coder encodeValueOfObjCType: @encode(unsigned int) at: &_fetchLimit]; + [coder encodeObject: _prefetchingRelationshipKeys]; + [coder encodeObject: _rawAttributeKeys]; + [coder encodeValueOfObjCType: @encode(unsigned int) at: &_flags]; +} + +- (id)initWithCoder: (NSCoder *)coder +{ + _qualifier = [[coder decodeObject] retain]; + _sortOrderings = [[coder decodeObject] retain]; + _entityName = [[coder decodeObject] retain]; + _hints = [[coder decodeObject] retain]; + [coder decodeValueOfObjCType: @encode(unsigned int) at: &_fetchLimit]; + _prefetchingRelationshipKeys = [[coder decodeObject] retain]; + _rawAttributeKeys = [[coder decodeObject] retain]; + [coder decodeValueOfObjCType: @encode(unsigned int) at: &_flags]; + + return self; +} + +- (id) initWithKeyValueUnarchiver: (EOKeyValueUnarchiver*)unarchiver +{ + if ((self = [self init])) + { + ASSIGN(_hints, [unarchiver decodeObjectForKey: @"hints"]); + ASSIGN(_qualifier, [unarchiver decodeObjectForKey: @"qualifier"]); + ASSIGN(_sortOrderings, [unarchiver decodeObjectForKey: @"sortOrderings"]); + ASSIGN(_entityName, [unarchiver decodeObjectForKey: @"entityName"]); + ASSIGN(_prefetchingRelationshipKeys, + [unarchiver decodeObjectForKey: @"prefetchingRelationshipKeyPaths"]); + ASSIGN(_rawAttributeKeys, [unarchiver decodeObjectForKey: @"rawRowKeyPaths"]); + + _fetchLimit = [unarchiver decodeIntForKey: @"fetchLimit"]; + _flags.usesDistinct = [unarchiver decodeBoolForKey: @"usesDistinct"]; + _flags.isDeep = [unarchiver decodeBoolForKey: @"isDeep"]; + _flags.locksObjects = [unarchiver decodeBoolForKey: @"locksObjects"]; + _flags.refreshesRefetchedObjects = + [unarchiver decodeBoolForKey: @"refreshesRefetchedObjects"]; + _flags.promptsAfterFetchLimit = + [unarchiver decodeBoolForKey: @"promptsAfterFetchLimit"]; + _flags.allVariablesRequiredFromBindings = + [unarchiver decodeBoolForKey: @"requiresAllQualifierBindingVariables"]; + } + + return self; +} + +- (void) encodeWithKeyValueArchiver: (EOKeyValueUnarchiver*)archiver +{ + [self notImplemented: _cmd]; +} + +- (NSString*)description +{ + NSMutableString *desc = [NSMutableString string]; + + [desc appendString: @"{\n"]; + [desc appendString: [NSString stringWithFormat: @"hints = %@;\n", + [_hints description]]]; + [desc appendString: [NSString stringWithFormat: @"qualifier = %@;\n", + _qualifier]]; + [desc appendString: [NSString stringWithFormat: @"sortOrderings = %@;\n", + [_sortOrderings description]]]; + [desc appendString: [NSString stringWithFormat: @"entityName = %@;\n", + _entityName]]; + [desc appendString: [NSString stringWithFormat: @"prefetchingRelationshipKeyPaths = %@;\n", + [_prefetchingRelationshipKeys description]]]; + [desc appendString: [NSString stringWithFormat: @"rawRowKeyPaths = %@;\n", + [_rawAttributeKeys description]]]; + [desc appendString: [NSString stringWithFormat: @"fetchLimit = %d;\n", + _fetchLimit]]; + [desc appendString: [NSString stringWithFormat: @"usesDistinct = %s;\n", + _flags.usesDistinct ? "YES" : "NO"]]; + [desc appendString: [NSString stringWithFormat: @"isDeep = %s;\n", + _flags.isDeep ? "YES" : "NO"]]; + [desc appendString: [NSString stringWithFormat: @"locksObjects = %s;\n", + _flags.locksObjects ? "YES" : "NO"]]; + [desc appendString: [NSString stringWithFormat: @"refreshesRefetchedObjects = %s;\n", + _flags.refreshesRefetchedObjects ? "YES" : "NO"]]; + [desc appendString: [NSString stringWithFormat: @"promptsAfterFetchLimit = %s;\n", + _flags.promptsAfterFetchLimit ? "YES" : "NO"]]; + [desc appendString: [NSString stringWithFormat: @"requiresAllQualifierBindingVariables = %s;\n", + _flags.allVariablesRequiredFromBindings ? "YES" : "NO"]]; + [desc appendString: @"}"]; + + return desc; +} + +- (void)setEntityName: (NSString *)entityName +{ + [self willChange]; + ASSIGN(_entityName, entityName); +} + +- (NSString *)entityName +{ + return _entityName; +} + +- (void)setSortOrderings: (NSArray *)sortOrderings +{ + ASSIGN(_sortOrderings, sortOrderings); +} + +- (NSArray *)sortOrderings +{ + return _sortOrderings; +} + +- (void)setQualifier: (EOQualifier *)qualifier +{ + [self willChange]; + ASSIGN(_qualifier, qualifier); +} + +- (EOQualifier *)qualifier +{ + return _qualifier; +} + +- (void)setUsesDistinct: (BOOL)usesDistinct +{ + [self willChange]; + _flags.usesDistinct = usesDistinct; +} + +- (BOOL)usesDistinct +{ + return _flags.usesDistinct; +} + +- (void)setIsDeep: (BOOL)isDeep +{ + [self willChange]; + _flags.isDeep = isDeep; +} + +- (BOOL)isDeep +{ + return _flags.isDeep; +} + +- (void)setLocksObjects: (BOOL)locksObjects +{ + [self willChange]; + _flags.locksObjects = locksObjects; +} + +- (BOOL)locksObjects +{ + return _flags.locksObjects; +} + +- (void)setRefreshesRefetchedObjects: (BOOL)refreshesRefetchedObjects +{ + [self willChange]; + _flags.refreshesRefetchedObjects = refreshesRefetchedObjects; +} + +- (BOOL)refreshesRefetchedObjects +{ + return _flags.refreshesRefetchedObjects; +} + +- (void)setFetchLimit: (unsigned)fetchLimit +{ + [self willChange]; + _fetchLimit = fetchLimit; +} + +- (unsigned)fetchLimit +{ + return _fetchLimit; +} + +- (void)setPromptsAfterFetchLimit: (BOOL)promptsAfterFetchLimit +{ + [self willChange]; + _flags.promptsAfterFetchLimit = promptsAfterFetchLimit; +} + +- (BOOL)promptsAfterFetchLimit +{ + return _flags.promptsAfterFetchLimit; +} + +- (void)setAllVariablesRequiredFromBindings: (BOOL)allVariablesRequired +{ + _flags.allVariablesRequiredFromBindings = allVariablesRequired; +} + +- (BOOL)allVariablesRequiredFromBindings +{ + return _flags.allVariablesRequiredFromBindings; +} + +- (void)setPrefetchingRelationshipKeyPaths: (NSArray *)prefetchingRelationshipKeys +{ + [self willChange]; + ASSIGN(_prefetchingRelationshipKeys, prefetchingRelationshipKeys); +} + +- (NSArray *)prefetchingRelationshipKeyPaths +{ + return _prefetchingRelationshipKeys; +} + +- (void)setRawAttributeKeys: (NSArray *)rawAttributeKeys +{ + ASSIGN(_rawAttributeKeys, rawAttributeKeys); +} + +- (NSArray *)rawAttributeKeys +{ + return _rawAttributeKeys; +} + +- (void)setFetchesRawRows: (BOOL)fetchRawRows +{ + if (fetchRawRows) + [self setRawRowKeyPaths: [NSArray array]]; + else + [self setRawRowKeyPaths: nil]; +} + +- (BOOL)fetchesRawRows +{ + if ([self rawRowKeyPaths]) + return YES; + else + return NO; +} + +- (void)setHints: (NSDictionary *)hints +{ + //TODO: set fetchLimit,... from hints ??? + [self willChange]; +//even if nil: initWithDictionary:copyItems: +//thedict objectForKey:EOPrefetchingRelationshipHintKey +//EOFetchLimitHintKey +//EOPromptAfterFetchLimitHintKey + ASSIGN(_hints, hints); +} + +- (NSDictionary *)_hints +{ + return _hints; +} + +- (NSDictionary *)hints +{ + NSMutableDictionary *hints = _hints; + BOOL promptsAfterFetchLimit; + NSArray *prefetchingRelationshipKeyPaths; + unsigned fetchLimit; + + fetchLimit = [self fetchLimit]; + promptsAfterFetchLimit = [self promptsAfterFetchLimit]; + prefetchingRelationshipKeyPaths = [self prefetchingRelationshipKeyPaths]; + + if (fetchLimit != 0 || promptsAfterFetchLimit + || [prefetchingRelationshipKeyPaths count] > 0) + { + NSMutableDictionary *mutableHints = [NSMutableDictionary + dictionaryWithDictionary: hints]; + + hints = mutableHints; + + if (fetchLimit != 0) + { + [mutableHints setObject: [NSNumber numberWithInt: fetchLimit] + forKey: @"EOFetchLimitHintKey"]; + } + + if (promptsAfterFetchLimit) + { + [mutableHints setObject: [NSNumber numberWithBool: + promptsAfterFetchLimit] + forKey: @"EOPromptAfterFetchLimitHintKey"]; + } + + if ([prefetchingRelationshipKeyPaths count] > 0) + { + [mutableHints setObject: prefetchingRelationshipKeyPaths + forKey: @"EOPrefetchingRelationshipHintKey"]; + } + } + + return hints; +} + +- (NSArray *)rawRowKeyPaths +{ + return _rawAttributeKeys; +} + +- (void)setRawRowKeyPaths: (NSArray *)rawRowKeyPaths +{ + [self willChange]; + ASSIGN(_rawAttributeKeys, rawRowKeyPaths); +} + +- (BOOL)requiresAllQualifierBindingVariables +{ + NSDebugMLLog(@"gsdb", @"self=%p", self); + return _flags.allVariablesRequiredFromBindings; +} + +- (void)setRequiresAllQualifierBindingVariables: (BOOL)flag +{ + [self willChange]; + [self notImplemented: _cmd]; +} + +@end diff --git a/EOControl/EOGenericRecord.h b/EOControl/EOGenericRecord.h new file mode 100644 index 0000000..a8f4080 --- /dev/null +++ b/EOControl/EOGenericRecord.h @@ -0,0 +1,61 @@ +/* + EOGenericRecord.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: June 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOGenericRecord_h__ +#define __EOGenericRecord_h__ + +#import + +@class NSString; +@class NSMutableDictionary; +@class EOClassDescription; +@class EOEditingContext; +@class EOGlobalID; +@class EOMutableKnownKeyDictionary; + +@interface EOGenericRecord : NSObject +{ + EOClassDescription *classDescription; + EOMutableKnownKeyDictionary *dictionary; +} + +// Initializing new instances + +- initWithEditingContext: (EOEditingContext *)context + classDescription: (EOClassDescription *)classDesc + globalID: (EOGlobalID *)globalID; + +- (id)valueForKey: (NSString *)key; +- (void)takeValue: (id)value + forKey: (NSString *)key; + ++ (void)eoCalculateAllSizeWith: (NSMutableDictionary*)dict; +- (unsigned int)eoCalculateSizeWith: (NSMutableDictionary*)dict; + +@end /* EOGenericRecord */ + + +#endif /* __EOGenericRecord_h__ */ diff --git a/EOControl/EOGenericRecord.m b/EOControl/EOGenericRecord.m new file mode 100644 index 0000000..37f32b4 --- /dev/null +++ b/EOControl/EOGenericRecord.m @@ -0,0 +1,1354 @@ +/** + EOGenericRecord.m EOGenericRecord + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: June 2000 + + Author: Manuel Guesdon + Date: October 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import + +#import +#import +#import + +#import +#import + +#import +#import +#import +#import +#import +#import +#import + + + +@interface NSObject (EOCalculateSize) +- (unsigned int)eoGetSize; +@end + +@interface NSString (EOCalculateSize) +- (unsigned int)eoGetSize; +@end + + +@interface NSArray (EOCalculateSize) +- (unsigned int)eoCalculateSizeWith: (NSMutableDictionary *)dict; +@end + +@interface NSDictionary (EOCalculateSize) +- (unsigned int)eoCalculateSizeWith: (NSMutableDictionary *)dict; +@end + +@interface EOFault (EOCalculateSize) ++ (unsigned int)eoCalculateSizeWith: (NSMutableDictionary *)dict + forFault: (id)object; +@end + + +static NSHashTable *allGenericRecords = NULL; +static NSRecursiveLock *allGenericRecordsLock = nil; + + +@implementation EOGenericRecord + ++ (void) initialize +{ + if ([[super superclass] initialize]) + { + if (self == [EOGenericRecord class]) + { + allGenericRecords = NSCreateHashTable(NSNonOwnedPointerHashCallBacks, + 1000); + allGenericRecordsLock = [NSRecursiveLock new]; + } + } +} + ++ (void)addCreatedObject: (EOGenericRecord *)o +{ + [allGenericRecordsLock lock]; + NSHashInsertIfAbsent(allGenericRecords, o); + [allGenericRecordsLock unlock]; +} + ++ (void)removeDestoyedObject: (EOGenericRecord *)o +{ + [allGenericRecordsLock lock]; + NSHashRemove(allGenericRecords, o); + [allGenericRecordsLock unlock]; +} + +- (id) init +{ + if ((self = [super init])) + { + [[self class] addCreatedObject: self]; + } + + return self; +} + +- (id) initWithEditingContext: (EOEditingContext *)context + classDescription: (EOClassDescription *)classDesc + globalID: (EOGlobalID *)globalID; +{ + if ((self = [self init])) + { + EOEntity *entity = nil; + EOMutableKnownKeyDictionary *entityMKKD = nil; + + if (!classDesc) + { + [NSException raise: NSInternalInconsistencyException + format: @"%@ -- %@ 0x%x: attempt to initialize object with nil classDescription", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self]; + + [self autorelease]; + return nil; + } + + ASSIGN(classDescription, classDesc); + + entity = [(EOEntityClassDescription*)classDesc entity]; + NSAssert(entity, @"No entity"); + + entityMKKD = [entity _dictionaryForProperties]; + + ASSIGN(dictionary,entityMKKD); + EOFLOGObjectLevelArgs(@"EOGenericRecord", @"Record %p: dictionary=%@", + self, dictionary); + } + + return self; +} + +- (void)dealloc +{ + EOFLOGObjectLevelArgs(@"EOGenericRecord", + @"Deallocate EOGenericRecord %p (dict=%p)", + self, dictionary); + + [[self class] removeDestoyedObject: self]; + + DESTROY(classDescription); + DESTROY(dictionary); + + [super dealloc]; +} + +- (EOClassDescription*)classDescription +{ + return classDescription; +} + +static const char _c_id[2] = { _C_ID, NULL }; + +//used to allow derived object implementation +- (BOOL)_infoForInstanceVariableNamed: (NSString*)name + retType: (const char**)type + retSize: (unsigned*)size + retOffset: (unsigned*)offset +{ + BOOL ok; + + EOFLOGObjectFnStartCond(@"EOGenericRecordKVC"); +/* ok=[super _infoForInstanceVariableNamed:name + retType:type + retSize:size + retOffset:offset]; +*/ + ok = GSInstanceVariableInfo(self, name, type, size, offset); + + EOFLOGObjectLevelArgs(@"EOGenericRecordKVC", + @"Super InstanceVar named %@:%s", + name, (ok ? "YES" : "NO")); + + if (!ok) + { + EOFLOGObjectLevelArgs(@"EOGenericRecordKVC", + @"dictionary: %p eoMKKDInitializer: %p", + dictionary, + [dictionary eoMKKDInitializer]); + EOFLOGObjectLevelArgs(@"EOGenericRecordKVC", @"dictionary allkeys= %@", + [dictionary allKeys]); + + if ([dictionary hasKey: name]) + { + if (type) + *type = _c_id; + if (size) + *size = sizeof(id); + if (offset) + *offset = UINT_MAX; //Special Marker + + ok = YES; + + EOFLOGObjectLevelArgs(@"EOGenericRecordKVC", + @"Self InstanceVar named %@:%s", + name, (ok ? "YES" : "NO")); + } + } + + EOFLOGObjectFnStopCond(@"EOGenericRecordKVC"); + + return ok; +} + +//used to allow derived object implementation +- (id)_getValueForKey: (NSString*)aKey + selector: (SEL)sel + type: (const char*)type + size: (unsigned)size + offset: (unsigned)offset +{ + id value = nil; + + EOFLOGObjectFnStartCond(@"EOGenericRecordKVC"); + EOFLOGObjectLevelArgs(@"EOGenericRecordKVC", + @"Super InstanceVar named %@: offset=%u", + aKey, offset); + + if (offset == UINT_MAX) + { + value = [dictionary objectForKey: aKey]; + + EOFLOGObjectLevelArgs(@"EOGenericRecordKVC", @"value %p (class=%@)", + value, [value class]); + } + else + { + /* value=[super _getValueForKey:aKey + selector:sel + type:type + size:size + offset:offset];*/ + + value = GSGetValue(self, aKey, sel, type, size, offset); + EOFLOGObjectLevelArgs(@"EOGenericRecordKVC", @"value %p (class=%@)", + value, [value class]); + } + + EOFLOGObjectFnStopCond(@"EOGenericRecordKVC"); + + return value; +} + +//used to allow derived object implementation +- (void)_setValueForKey: (NSString *)aKey + object: (id)anObject + selector: (SEL)sel + type: (const char*)type + size: (unsigned)size + offset: (unsigned)offset +{ + EOFLOGObjectFnStartCond(@"EOGenericRecordKVC"); + EOFLOGObjectLevelArgs(@"EOGenericRecordKVC", + @"Super InstanceVar named %@: offset=%u", + aKey, offset); + + [self willChange]; + + if (offset == UINT_MAX) + { + if (anObject) + [dictionary setObject: anObject + forKey: aKey]; + else + [dictionary removeObjectForKey: aKey]; + } + else +/* [super _setValueForKey:aKey + object:anObject + selector:sel + type:type + size:size + offset:offset]; +*/ + GSSetValue(self, aKey, anObject, sel, type, size, offset); + + EOFLOGObjectFnStopCond(@"EOGenericRecordKVC"); +} + +//used to allow derived object implementation +- (id) _handleQueryWithUnboundKey: (NSString*)aKey +{ + return nil; +} + +//used to allow derived object implementation +- (void) _handleTakeValue: (id)anObject forUnboundKey: (NSString*)aKey +{ +} + +/* +- (void)takeStoredValue:(id)value + forKey:(NSString *)key +{ + EOFLOGObjectFnStartOrCond(@"EOGenericRecord"); + EOFLOGObjectLevelArgs(@"EOGenericRecord", @"key=%@", key); + [super takeStoredValue: value + forKey: key]; + EOFLOGObjectFnStopOrCond(@"EOGenericRecord"); +} + +- (void)takeValue:(id)value + forKey:(NSString *)key +{ + EOFLOGObjectFnStartOrCond(@"EOGenericRecord"); + EOFLOGObjectLevelArgs(@"EOGenericRecord", @"key=%@", key); + + [self willChange]; + + [super takeValue: value + forKey: key]; + EOFLOGObjectFnStopOrCond(@"EOGenericRecord"); +// +// if(value == nil || value == [EONull null]) +// [dictionary removeObjectForKey:key]; +// else +// { +// NSArray *attrKeys, *toManyKeys, *toOneKeys; +// +// attrKeys = [classDescription attributeKeys]; +// toManyKeys = [classDescription toManyRelationshipKeys]; +// toOneKeys = [classDescription toOneRelationshipKeys]; +// +// if([attrKeys containsObject:key] == NO && +// [toManyKeys containsObject:key] == NO && +// [toOneKeys containsObject:key] == NO) +// return; +// +// [dictionary setObject:value forKey:key]; +// } +// +// EOFLOGObjectFnStopOrCond(@"EOGenericRecord"); +} + +- (id)storedValueForKey:(NSString *)key +{ + id value=nil; + EOFLOGObjectFnStartOrCond(@"EOGenericRecord"); + EOFLOGObjectLevelArgs(@"EOGenericRecord",@"key=%@",key); + value=[super storedValueForKey: key]; + EOFLOGObjectFnStopOrCond(@"EOGenericRecord"); + return value; +} + +- (id)valueForKey:(NSString *)key +{ + id value=nil; + EOFLOGObjectFnStartOrCond(@"EOGenericRecord"); + EOFLOGObjectLevelArgs(@"EOGenericRecord", @"key=%@", key); + value=[super valueForKey: key]; + EOFLOGObjectFnStopOrCond(@"EOGenericRecord"); + return value; +// id value=nil; +// EOFLOGObjectFnStartOrCond(@"EOGenericRecord"); +// EOFLOGObjectLevelArgs(@"EOGenericRecord", @"key=%@", key); +// NSArray *attrKeys, *toManyKeys, *toOneKeys; +// +// attrKeys = [classDescription attributeKeys]; +// toManyKeys = [classDescription toManyRelationshipKeys]; +// toOneKeys = [classDescription toOneRelationshipKeys]; +// +// if([attrKeys containsObject:key] == NO && +// [toManyKeys containsObject:key] == NO && +// [toOneKeys containsObject:key] == NO) +// return nil; +// +// value=[dictionary objectForKey:key]; +// EOFLOGObjectFnStopOrCond(@"EOGenericRecord"); +// return value; +} +*/ + +- (id) storedValueForKey: (NSString*)aKey +{ + SEL sel = 0; + const char *type = NULL; + unsigned size = 0; + unsigned off = 0; + NSString *name = nil; + NSString *cap = nil; + id value = nil; + + EOFLOGObjectFnStartCond(@"EOGenericRecordKVC"); + EOFLOGObjectLevelArgs(@"EOGenericRecordKVC", @"aKey=%@", aKey); + + if ([[self class] useStoredAccessor] == NO) + { + value = [self valueForKey: aKey]; + } + else + { + size = [aKey length]; + + if (size < 1) + { + [NSException raise: NSInvalidArgumentException + format: @"storedValueForKey: ... empty key"]; + } + + cap = [[aKey substringToIndex: 1] uppercaseString]; + if (size > 1) + { + cap = [cap stringByAppendingString: [aKey substringFromIndex: 1]]; + } + + name = [NSString stringWithFormat: @"_get%@", cap]; + sel = NSSelectorFromString(name); + + if (sel == 0 || [self respondsToSelector: sel] == NO) + { + name = [NSString stringWithFormat: @"_%@", aKey]; + sel = NSSelectorFromString(name); + + if (sel == 0 || [self respondsToSelector: sel] == NO) + { + sel = 0; + } + } + + if (sel == 0) + { + if ([[self class] accessInstanceVariablesDirectly] == YES) + { + name = [NSString stringWithFormat: @"_%@", aKey]; + + if ([self _infoForInstanceVariableNamed:name + retType: &type + retSize: &size + retOffset: &off]==NO) + { + name = aKey; + [self _infoForInstanceVariableNamed:name + retType: &type + retSize: &size + retOffset: &off]; + } + } + + if (type == NULL) + { + name = [NSString stringWithFormat: @"get%@", cap]; + sel = NSSelectorFromString(name); + + if (sel == 0 || [self respondsToSelector: sel] == NO) + { + name = aKey; + sel = NSSelectorFromString(name); + + if (sel == 0 || [self respondsToSelector: sel] == NO) + { + sel = 0; + } + } + } + } + + value = [self _getValueForKey: aKey + selector: sel + type: type + size: size + offset: off]; + + } + + EOFLOGObjectLevelArgs(@"EOGenericRecordKVC", @"value=%@", value); + EOFLOGObjectFnStopCond(@"EOGenericRecordKVC"); + + return value; +} + +- (void) takeStoredValue: (id)anObject + forKey: (NSString*)aKey +{ + SEL sel = NULL; + const char *type = NULL; + unsigned size = 0; + unsigned off = 0; + NSString *cap = nil; + NSString *name = nil; + + EOFLOGObjectFnStartCond(@"EOGenericRecordKVC"); + EOFLOGObjectLevelArgs(@"EOGenericRecordKVC", @"anObject=%@", anObject); + EOFLOGObjectLevelArgs(@"EOGenericRecordKVC", @"aKey=%@", aKey); + + if ([[self class] useStoredAccessor] == NO) + { + EOFLOGObjectLevelArgs(@"EOGenericRecordKVC", @"aKey=%@", aKey); + + [self takeValue: anObject + forKey: aKey]; + } + else + { + size = [aKey length]; + + if (size < 1) + { + [NSException raise: NSInvalidArgumentException + format: @"takeStoredValue:forKey: ... empty key"]; + } + + cap = [[aKey substringToIndex: 1] uppercaseString]; + if (size > 1) + { + cap = [cap stringByAppendingString: [aKey substringFromIndex: 1]]; + } + + name = [NSString stringWithFormat: @"_set%@:", cap]; + type = NULL; + sel = NSSelectorFromString(name); + + if (sel == 0 || [self respondsToSelector: sel] == NO) + { + sel = 0; + + if ([[self class] accessInstanceVariablesDirectly] == YES) + { + name = [NSString stringWithFormat: @"_%@", aKey]; + + EOFLOGObjectLevelArgs(@"EOGenericRecordKVC", @"aKey=%@ name=%@", + aKey, name); + + if ([self _infoForInstanceVariableNamed: name + retType: &type + retSize: &size + retOffset: &off]==NO) + { + name = aKey; + + EOFLOGObjectLevelArgs(@"EOGenericRecordKVC", + @"aKey=%@ name=%@", aKey, name); + + [self _infoForInstanceVariableNamed: name + retType: &type + retSize: &size + retOffset: &off]; + } + } + + if (type == NULL) + { + name = [NSString stringWithFormat: @"set%@:", cap]; + + EOFLOGObjectLevelArgs(@"EOGenericRecordKVC", @"aKey=%@ name=%@", + aKey, name); + + sel = NSSelectorFromString(name); + + if (sel == 0 || [self respondsToSelector: sel] == NO) + { + sel = 0; + } + } + } + + EOFLOGObjectLevelArgs(@"EOGenericRecordKVC", + @"class=%@ aKey=%@ sel=%p offset=%u", + [self class], aKey, sel, off); + + [self _setValueForKey: aKey + object: anObject + selector: sel + type: type + size: size + offset: off]; + } + + EOFLOGObjectFnStopCond(@"EOGenericRecordKVC"); +} + +/** if key is a bidirectional rel, use addObject:toBothSidesOfRelationship otherwise call takeValue:forKey: **/ +- (void)smartTakeValue: (id)anObject + forKey: (NSString *)aKey +{ + EORelationship *rel = [classDescription relationshipNamed: aKey]; + + //NSDebugMLog(@"aKey=%@ rel=%@ anObject=%@", aKey, rel, anObject); + //NSDebugMLog(@"[rel isBidirectional]=%d", [rel isBidirectional]); + + if (rel && [rel isBidirectional]) + { + if (isNilOrEONull(anObject)) + { + id oldObj = [self valueForKey: aKey]; + + if (isNilOrEONull(oldObj)) + { + if (![rel isToMany]) + [self takeValue: anObject + forKey: aKey]; + } + else + [self removeObject: anObject + fromBothSidesOfRelationshipWithKey: aKey]; + } + else + [self addObject: anObject + toBothSidesOfRelationshipWithKey: aKey]; + } + else + [self takeValue: anObject + forKey: aKey]; +} + +- (void) takeValue: (id)anObject forKey: (NSString*)aKey +{ + SEL sel; + const char *type; + unsigned size; + unsigned off=0; + NSString *cap; + NSString *name; + + EOFLOGObjectFnStartCond(@"EOGenericRecordKVC"); + EOFLOGObjectLevelArgs(@"EOGenericRecordKVC", @"anObject=%@", anObject); + EOFLOGObjectLevelArgs(@"EOGenericRecordKVC", @"aKey=%@", aKey); + + size = [aKey length]; + if (size < 1) + { + [NSException raise: NSInvalidArgumentException + format: @"takeValue:forKey: ... empty key"]; + } + + cap = [[aKey substringToIndex: 1] uppercaseString]; + if (size > 1) + { + cap = [cap stringByAppendingString: [aKey substringFromIndex: 1]]; + } + + name = [NSString stringWithFormat: @"set%@:", cap]; + type = NULL; + sel = NSSelectorFromString(name); + + if (sel == 0 || [self respondsToSelector: sel] == NO) + { + name = [NSString stringWithFormat: @"_set%@:", cap]; + sel = NSSelectorFromString(name); + + if (sel == 0 || [self respondsToSelector: sel] == NO) + { + sel = 0; + + if ([[self class] accessInstanceVariablesDirectly] == YES) + { + name = [NSString stringWithFormat: @"_%@", aKey]; + + if ([self _infoForInstanceVariableNamed: name + retType: &type + retSize: &size + retOffset: &off]==NO) + { + name = aKey; + + [self _infoForInstanceVariableNamed: name + retType: &type + retSize: &size + retOffset: &off]; + } + } + } + } + + [self _setValueForKey: aKey + object: anObject + selector: sel + type: type + size: size + offset: off]; + + EOFLOGObjectFnStopCond(@"EOGenericRecordKVC"); +} + +- (id) valueForKey: (NSString*)aKey +{ + SEL sel = 0; + NSString *cap; + NSString *name = nil; + const char *type = NULL; + unsigned size; + unsigned off = 0; + id value = nil; + + EOFLOGObjectFnStartCond(@"EOGenericRecordKVC"); + EOFLOGObjectLevelArgs(@"EOGenericRecordKVC", @"aKey=%@", aKey); + + size = [aKey length]; + if (size < 1) + { + [NSException raise: NSInvalidArgumentException + format: @"valueForKey: ... empty key"]; + } + + cap = [[aKey substringToIndex: 1] uppercaseString]; + if (size > 1) + { + cap = [cap stringByAppendingString: [aKey substringFromIndex: 1]]; + } + + name = [@"get" stringByAppendingString: cap]; + sel = NSSelectorFromString(name); + + if (sel == 0 || [self respondsToSelector: sel] == NO) + { + name = aKey; + sel = NSSelectorFromString(name); + + if (sel == 0 || [self respondsToSelector: sel] == NO) + { + name = [@"_get" stringByAppendingString: cap]; + sel = NSSelectorFromString(name); + + if (sel == 0 || [self respondsToSelector: sel] == NO) + { + name = [NSString stringWithFormat: @"_%@", aKey]; + sel = NSSelectorFromString(name); + + if (sel == 0 || [self respondsToSelector: sel] == NO) + { + sel = 0; + } + } + } + } + + if (sel == 0 && [[self class] accessInstanceVariablesDirectly] == YES) + { + name = [NSString stringWithFormat: @"_%@", aKey]; + + if ([self _infoForInstanceVariableNamed: name + retType: &type + retSize: &size + retOffset: &off]==NO) + { + name = aKey; + + [self _infoForInstanceVariableNamed: name + retType: &type + retSize: &size + retOffset: &off]; + } + } + + value = [self _getValueForKey: aKey + selector: sel + type: type + size: size + offset: off]; + + EOFLOGObjectLevelArgs(@"EOGenericRecordKVC", @"value: %p (class=%@)", + value, [value class]); + EOFLOGObjectFnStopCond(@"EOGenericRecordKVC"); + + return value; +} + + + + +- (NSString *)description +{ + NSArray *toManyKeys = nil; + NSArray *toOneKeys = nil; + NSEnumerator *enumerator = [dictionary keyEnumerator]; + NSMutableDictionary *dict; + NSString *key = nil; + id obj = nil; + +// printf("descr %p\n",self); +// EOFLOGObjectFnStartOrCond(@"EOGenericRecord"); +/* int num=0;//TODELETE + EOFLOGObjectLevelArgs(@"EOGenericRecord",@"self=%p dict=%p enumerator=%@",self,dictionary,enumerator); + fflush(stdout); + fflush(stderr); + EOFLOGObjectLevelArgs(@"EOGenericRecord",@"classDescription=%@",classDescription); + fflush(stdout); + fflush(stderr); +*/ + toManyKeys = [classDescription toManyRelationshipKeys]; + toOneKeys = [classDescription toOneRelationshipKeys]; +/* + EOFLOGObjectLevelArgs(@"EOGenericRecord",@"AAAA"); + fflush(stdout); + fflush(stderr); + EOFLOGObjectLevelArgs(@"EOGenericRecord",@"toManyKeys=%@",toManyKeys); + fflush(stdout); + fflush(stderr); + EOFLOGObjectLevelArgs(@"EOGenericRecord",@"toOneKeys=%@",toOneKeys); + fflush(stdout); + fflush(stderr); +*/ + dict = [NSMutableDictionary dictionaryWithCapacity: [dictionary count]]; +// EOFLOGObjectLevelArgs(@"EOGenericRecord",@"Values nb=%d",[dictionary count]); + + while ((key = [enumerator nextObject])) + { + //EOFLOGObjectLevelArgs(@"EOGenericRecord", @"%d key=%@", num, key); + + obj = [dictionary objectForKey: key]; + + if (!obj) + [dict setObject: @"(null)" + forKey: key]; + else + { + //EOFLOGObjectLevelArgs(@"EOGenericRecord", @"%d obj=%@", num, obj); + //EOFLOGObjectLevelArgs(@"EOGenericRecord", @"%d key=%@", num, key); + //EOFLOGObjectLevelArgs(@"EOGenericRecord", @"%d obj=%@", num, obj); + + if ([toManyKeys containsObject: key] == NO + && [toOneKeys containsObject: key] == NO) + { + //EOFLOGObjectLevelArgs(@"EOGenericRecord", @"%d SIMPLE VALUE", num); + //EOFLOGObjectLevelArgs(@"EOGenericRecord", @"%d dict=%@", num, dict); + [dict setObject: obj + forKey: key]; + //EOFLOGObjectLevelArgs(@"EOGenericRecord", @"%d dict=%@", num, dict); + } + else + { + //EOFLOGObjectLevelArgs(@"EOGenericRecord", @"%d NOT SIMPLE VALUE", num); + if ([EOFault isFault: obj] == YES) + { + //EOFLOGObjectLevelArgs(@"EOGenericRecord", @"%d FAULT VALUE", num); + [dict setObject: [obj description] + forKey: key]; + } + else if ([toManyKeys containsObject: key] == YES) + { + NSEnumerator *toManyEnum; + NSMutableArray *array; + id rel; + + //EOFLOGObjectLevelArgs(@"EOGenericRecord", @"%d TO MANY VALUE", num); + + array = [NSMutableArray arrayWithCapacity: 8]; + toManyEnum = [obj objectEnumerator]; + + while ((rel = [toManyEnum nextObject])) + { + /* [array addObject: + [NSString + stringWithFormat:@"<%@: classDescription=%@>", + NSStringFromClass([obj class]), + [obj classDescription]]]; + */ + [array addObject: + [NSString + stringWithFormat: @"<%@ %p>", + rel, NSStringFromClass([rel class])]]; + } + + [dict setObject: [NSString stringWithFormat: + @"<%p %@ : %@>", + obj, [obj class], array] + forKey: key]; + } + else + { + //EOFLOGObjectLevelArgs(@"EOGenericRecord", @"%d TO ONE VALUE", num); + [dict setObject: [NSString + stringWithFormat: @"<%p %@: classDescription=%@>", + obj, + NSStringFromClass([obj class]), + [obj classDescription]] + forKey: key]; + } + //EOFLOGObjectLevelArgs(@"EOGenericRecord", @"%d END VALUE", num); + } + } + } + + //EOFLOGObjectLevelArgs(@"EOGenericRecord", @"END DESCR"); + //EOFLOGObjectLevelArgs(@"EOGenericRecord", @"dictionary=%@", dictionary); +// EOFLOGObjectFnStopOrCond(@"EOGenericRecord"); +// printf("end descr %p\n",self); + + return [NSString stringWithFormat: @"<%s %p : classDescription=%@\nvalues=%@>", + object_get_class_name(self), + (void*)self, + classDescription, + dict]; +// return @""; +} + +//debug only +- (NSString *)debugDictionaryDescription +{ + return [dictionary debugDescription]; +} + +/*dictionary has following entries: + - NSMutableDictionary* processed: processed entries (key=object address, value=size) + - NSMutableDictionary* summaryNb: objects by class name (key=class name, value=number of objects) + - NSMutableDictionary* summarySize: objects by class name (key=class name, value=size) + - NSMutableArray* unknownClasses: not calculated objects classes + + size are size of objects + size of elementary included objects +*/ + ++ (void)eoCalculateAllSizeWith: (NSMutableDictionary *)dict +{ + EOGenericRecord *record = nil; + NSHashEnumerator hashEnum; + + EOFLOGClassFnStart(); + //NSDebugMLog(@"CALCULATE START"); + + [allGenericRecordsLock lock]; + + NS_DURING + { + hashEnum = NSEnumerateHashTable(allGenericRecords); + + while ((record = (EOGenericRecord*)NSNextHashEnumeratorItem(&hashEnum))) + { + [record eoCalculateSizeWith: dict]; + } + + NSEndHashTableEnumeration(&hashEnum); + } + NS_HANDLER + { + NSDebugMLog(@"%@ (%@)", localException, [localException reason]); + + [allGenericRecordsLock unlock]; + + NSDebugMLog(@"CALCULATE STOPEXC"); + [localException raise]; + } + NS_ENDHANDLER; + + [allGenericRecordsLock unlock]; + + //NSDebugMLog(@"CALCULATE STOP"); + EOFLOGClassFnStop(); +} + +- (unsigned int)eoCalculateSizeWith: (NSMutableDictionary *)dict +{ + NSMutableDictionary *processed; + NSValue *selfP; + + EOFLOGObjectFnStartOrCond(@"EOGenericRecord"); + //NSDebugMLog(@"CALCULATE OBJ START %p", self); + + processed = [dict objectForKey: @"processed"]; + selfP = [NSValue valueWithPointer: self]; + + if (![processed objectForKey: selfP]) + { + NSMutableDictionary *summaryNb = nil; + NSMutableDictionary *summarySize = nil; + NSMutableArray *unknownClasses = nil; + NSArray *props; + NSString *selfClassName = NSStringFromClass([self class]); + NSNumber *selfSummaryNb = nil; + NSNumber *selfSummarySize = nil; + unsigned int size = 0; + int i, propCount; + + //NSDebugMLog(@"self=%@",self); + + if (!processed) + { + processed = (NSMutableDictionary *)[NSMutableDictionary dictionary]; + [dict setObject: processed + forKey: @"processed"]; + } + + [processed setObject: [NSNumber numberWithUnsignedInt: 0] + forKey: selfP]; + + //NSDebugMLog(@"classDescription=%@", classDescription); + + props = [[(EOEntityClassDescription *)classDescription entity] + classPropertyNames]; + size += [self eoGetSize]; + size += [dictionary eoGetSize]; + + //NSDebugMLog(@"props=%@",props); + + propCount = [props count]; + + for (i = 0; i < propCount; i++) + { + NSString *propKey = [props objectAtIndex: i]; + id value = [self valueForKey: propKey]; + + //NSDebugMLog(@"propKey=%@", propKey); + //NSDebugMLog(@"value isFault=%s", ([EOFault isFault:value] ? "YES" : "NO")); + //NSDebugMLog(@"value=%p class=%@", value, [value class]); + + if (value) + { + if ([EOFault isFault:value]) + size += [EOFault eoCalculateSizeWith: dict + forFault: value]; + else if ([value respondsToSelector: @selector(eoCalculateSizeWith:)]) + { + size += [value eoCalculateSizeWith: dict]; + } + else if ([value respondsToSelector: @selector(eoGetSize)]) + size += [value eoGetSize]; + else + { + NSString *className = NSStringFromClass([value class]); + + if (!unknownClasses) + { + unknownClasses = [dict objectForKey: @"unknownClasses"]; + + if (!unknownClasses) + { + unknownClasses = [NSMutableArray array]; + [dict setObject: unknownClasses + forKey: @"unknownClasses"]; + } + } + + if (![unknownClasses containsObject: className]) + [unknownClasses addObject: className]; + } + } + } + + if (size > 0) + [processed setObject: [NSNumber numberWithUnsignedInt: size] + forKey: selfP]; + + summaryNb = [dict objectForKey: @"summaryNb"]; + + if (!summaryNb) + { + summaryNb = (NSMutableDictionary *)[NSMutableDictionary dictionary]; + [dict setObject: summaryNb + forKey: @"summaryNb"]; + } + + selfSummaryNb = [summaryNb objectForKey: selfClassName]; + selfSummaryNb = [NSNumber numberWithUnsignedInt: [selfSummaryNb + unsignedIntValue] + 1]; + [summaryNb setObject: selfSummaryNb + forKey: selfClassName]; + summarySize = [dict objectForKey: @"summarySize"]; + + if (!summarySize) + { + summarySize = (NSMutableDictionary *)[NSMutableDictionary dictionary]; + [dict setObject: summarySize + forKey: @"summarySize"]; + } + + selfSummarySize = [summarySize objectForKey: selfClassName]; + selfSummarySize = [NSNumber numberWithUnsignedInt: + [selfSummarySize unsignedIntValue] + size]; + + [summarySize setObject: selfSummarySize + forKey: selfClassName]; + } + + //NSDebugMLog(@"CALCULATE OBJ STOP %p", self); + EOFLOGObjectFnStopOrCond(@"EOGenericRecord"); + + return 0; +} + ++ (unsigned int)eoCalculateSizeWith: (NSMutableDictionary *)dict + forArray: (NSArray *)array +{ + NSMutableDictionary *processed; + NSValue *selfP; + + EOFLOGObjectFnStartOrCond(@"EOGenericRecord"); + //NSDebugMLog(@"CALCULATE ARRAY START %p", self); + + processed = [dict objectForKey: @"processed"]; + selfP = [NSValue valueWithPointer: array]; + + if (![processed objectForKey: selfP]) + { + int i, count; + + if (!processed) + { + processed = (NSMutableDictionary *)[NSMutableDictionary dictionary]; + [dict setObject: processed + forKey: @"processed"]; + } + + [processed setObject: [NSNumber numberWithUnsignedInt: 0] + forKey: selfP]; + + count = [array count]; + + for (i = 0; i < count; i++) + { + id value = [array objectAtIndex: i]; + + if (value) + { + if ([value respondsToSelector: @selector(eoCalculateSizeWith:)]) + [value eoCalculateSizeWith: dict]; + } + } + } + + //NSDebugMLog(@"CALCULATE ARRAY START %p", self); + EOFLOGClassFnStop(); + + return [array eoGetSize]; //return the base size +} + ++ (NSString *)eoFormatSizeDictionary: (NSDictionary *)dict +{ + NSMutableString *dscr = [NSMutableString string]; + NSMutableDictionary *processed; + NSMutableDictionary *summaryNb; + NSMutableDictionary *summarySize; + NSString *key; + unsigned totalSize = 0; + unsigned totalNb = 0; + NSEnumerator *enumK; + + EOFLOGClassFnStart(); + + processed = [dict objectForKey: @"processed"]; + summaryNb = [dict objectForKey: @"summaryNb"]; + summarySize = [dict objectForKey: @"summarySize"]; + enumK = [[[summaryNb allKeys] sortedArrayUsingSelector: + @selector(compare:)] objectEnumerator]; + + while ((key = [enumK nextObject])) + { + NSNumber *size = [summarySize objectForKey: key]; + NSNumber *number = [summaryNb objectForKey: key]; + + [dscr appendFormat: @"%@: totalSize=%@ bytes (%d Kb)/ objectsNb=%@ / meanSize=%d bytes (%d Kb)\n", + key, + size, + [size unsignedIntValue]/1024, + number, + (int)([size unsignedIntValue] / [number unsignedIntValue]), + (int)([size unsignedIntValue] / [number unsignedIntValue] / 1024)]; + + totalSize += [size unsignedIntValue]; + totalNb += [number unsignedIntValue]; + } + + [dscr appendFormat: @"-------------\ntotalSize=%u bytes (%d Kb) / objectsNb=%u / meanSize=%d bytes (%d Kb)\n", + totalSize, + totalSize / 1024, + totalNb, + (int)(totalSize / totalNb), + (int)(totalSize / totalNb / 1024)]; + + EOFLOGClassFnStop(); + + return dscr; +} + +@end /* EOGenericRecord */ + + +@implementation NSObject (EOCalculateSize) + +- (unsigned int)eoGetSize +{ + unsigned int size = 0; + Class selfClass = Nil; + +// EOFLOGObjectFnStartOrCond(@"EOGenericRecord"); + + selfClass = [self class]; + size = selfClass->instance_size; + +// EOFLOGObjectFnStopOrCond(@"EOGenericRecord"); + + return size; +} + +@end + +@implementation NSString (EOCalculateSize) + +- (unsigned int)eoGetSize +{ + unsigned int size; + //consider 2bytes string + + //EOFLOGObjectFnStartOrCond(@"EOGenericRecord"); + + size = [super eoGetSize] + [self length] * 2; + + //EOFLOGObjectFnStopOrCond(@"EOGenericRecord"); + + return size; +} + +@end + + +@implementation NSArray (EOCalculateSize) + +- (unsigned int)eoCalculateSizeWith: (NSMutableDictionary *)dict +{ + unsigned int size; + + //NSDebugMLog(@"CALCULATE ARRAY START %p", self); + + size = [EOGenericRecord eoCalculateSizeWith: dict + forArray: self]; + + //NSDebugMLog(@"CALCULATE ARRAY STOP %p", self); + + return size; +} + +@end + +@implementation NSDictionary (EOCalculateSize) + +- (unsigned int)eoCalculateSizeWith: (NSMutableDictionary *)dict +{ + //EOFLOGObjectFnStartOrCond(@"EOGenericRecord"); + + return [EOGenericRecord eoCalculateSizeWith: dict + forArray: [self allValues]]; + + //EOFLOGObjectFnStopOrCond(@"EOGenericRecord"); +} + +@end + +@implementation EOFault (EOCalculateSize) + ++ (unsigned int)eoCalculateSizeWith: (NSMutableDictionary *)dict + forFault: (id)object +{ + NSMutableDictionary *processed; + unsigned int baseSize = 0; + NSValue *objectP; + + EOFLOGClassFnStart(); + //NSDebugFLog(@"CALCULATE FAULT START %p",object); + + processed = [dict objectForKey: @"processed"]; + objectP = [NSValue valueWithPointer: object]; + + if (![processed objectForKey: objectP]) + { + NSString *objectClassName = [NSString stringWithFormat: @"%@ (Fault)", + NSStringFromClass([object class])]; + NSNumber *objectSummaryNb = 0; + NSNumber *objectSummarySize = 0; + Class objectClass = [object class]; + unsigned int size = 0; + + //NSDebugMLog(@"object=%p", object); + + if (!processed) + { + processed = (NSMutableDictionary *)[NSMutableDictionary dictionary]; + + [dict setObject: processed + forKey: @"processed"]; + } + + [processed setObject: [NSNumber numberWithUnsignedInt: 0] + forKey: objectP]; + size += objectClass->instance_size; + + if ([object isKindOfClass: [NSArray class]]) + baseSize += size; + else + { + NSMutableDictionary *summaryNb = nil; + NSMutableDictionary *summarySize = nil; + + if (size>0) + [processed setObject: [NSNumber numberWithUnsignedInt: size] + forKey: objectP]; + + summaryNb = [dict objectForKey: @"summaryNb"]; + if (!summaryNb) + { + summaryNb = (NSMutableDictionary *)[NSMutableDictionary + dictionary]; + + [dict setObject: summaryNb + forKey: @"summaryNb"]; + } + + objectSummaryNb = [summaryNb objectForKey: objectClassName]; + objectSummaryNb = [NSNumber numberWithUnsignedInt: + [objectSummaryNb unsignedIntValue] + 1]; + + [summaryNb setObject: objectSummaryNb + forKey: objectClassName]; + summarySize = [dict objectForKey: @"summarySize"]; + + if (!summarySize) + { + summarySize = (NSMutableDictionary *)[NSMutableDictionary + dictionary]; + + [dict setObject: summarySize + forKey: @"summarySize"]; + } + + objectSummarySize = [summarySize objectForKey: objectClassName]; + objectSummarySize = [NSNumber numberWithUnsignedInt: + [objectSummarySize unsignedIntValue] + + size]; + + [summarySize setObject: objectSummarySize + forKey: objectClassName]; + } + } + + //NSDebugMLog(@"CALCULATE FAULT STOP %p", object); + EOFLOGClassFnStop(); + + return baseSize; +} + +@end diff --git a/EOControl/EOGlobalID.h b/EOControl/EOGlobalID.h new file mode 100644 index 0000000..d716de7 --- /dev/null +++ b/EOControl/EOGlobalID.h @@ -0,0 +1,67 @@ +/* + EOGlobalID.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOGlobalID_h__ +#define __EOGlobalID_h__ + +#import + + +extern NSString *EOGlobalIDChangedNotification; + +@interface EOGlobalID : NSObject +- (BOOL)isEqual:other; +- (unsigned)hash; + +- (BOOL)isTemporary; + +@end + +enum { + EOUniqueBinaryKeyLength = 12 +}; + + +@interface EOTemporaryGlobalID : EOGlobalID +{ + unsigned _refCount; + unsigned char _bytes[EOUniqueBinaryKeyLength+1]; +} + ++ (EOTemporaryGlobalID *)temporaryGlobalID; ++ (void)assignGloballyUniqueBytes: (unsigned char *)buffer; + // < Sequence [2], ProcessID [2] , Time [4], IP Addr [4] > + +- init; + +- (BOOL)isTemporary; + +- (void)encodeWithCoder: (NSCoder *)aCoder; +- (id)initWithCoder: (NSCoder *)aDecoder; + +@end + +#endif diff --git a/EOControl/EOGlobalID.m b/EOControl/EOGlobalID.m new file mode 100644 index 0000000..c0234f2 --- /dev/null +++ b/EOControl/EOGlobalID.m @@ -0,0 +1,176 @@ +/** + EOGlobalID.m EOGlobalID + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import +#include +#include + +NSString *EOGlobalIDChangedNotification = @"EOGlobalIDChangedNotification"; + + +@implementation EOGlobalID + +- (BOOL)isEqual: other +{ + return NO; +} + +- (unsigned)hash +{ + return 0; +} + +- (BOOL)isTemporary +{ + return NO; +} + +- (id)copyWithZone: (NSZone *)zone +{ + EOGlobalID *gid = [[[self class] alloc] init]; + + return gid; +} + +@end + + +@implementation EOTemporaryGlobalID + +static unsigned short sequence = 65535; +static unsigned long sequenceRev = 0; + + ++ (EOTemporaryGlobalID *)temporaryGlobalID +{ + return [[[self alloc] init] autorelease]; +} + +// < Sequence [2], ProcessID [2] , Time [4], IP Addr [4] > ++ (void)assignGloballyUniqueBytes: (unsigned char *)buffer +{ + EOFLOGObjectFnStart(); + // sprintf(buffer, "%02x%02x%04x%04x", sequence++ % 0xff, 0, (unsigned int)time( NULL ) % 0xffffffff, 0); // <-- overwrite memory + + // buffer should have space for EOUniqueBinaryKeyLength (12) bytes. + // Assigns a world-wide unique ID made up of: + // < Sequence [2], ProcessID [2] , Time [4], IP Addr [4] > + + //printf("sequence : %d (%02x,%02x,%04x,%04x)\n",sequence -1, (sequence - 1) % 0xff, getpid() % 0xff, (unsigned int)time( NULL ) % 0xffff, (sequenceRev+1) % 0xffff); + + snprintf(buffer, 12, + "%02x%02x%04x%04x", + sequence-- % 0xff, + getpid() % 0xff, + (unsigned int)time( NULL ) % 0xffff, + sequenceRev++ % 0xffff); + + if (sequence == 0) + sequence = 65535; + + if (sequenceRev == 4294967295UL) + sequenceRev = 1; + + EOFLOGObjectFnStop(); + + return; // TODO +} + +- init +{ + EOFLOGObjectFnStart(); + + if ((self = [super init])) + { + [EOTemporaryGlobalID assignGloballyUniqueBytes:_bytes]; + } + + EOFLOGObjectFnStop(); + + return self; +} + +- (BOOL)isTemporary +{ + return YES; +} + +- (unsigned char *)_bytes +{ + return _bytes; +} + +- (BOOL)isEqual:other +{ + if (self == other) + return YES; + + if ([other isKindOfClass: [EOTemporaryGlobalID class]] == NO) + return NO; + + if (!memcmp(_bytes, [other _bytes], sizeof(_bytes))) + return YES; + + return NO; +} + +- (void)encodeWithCoder: (NSCoder *)coder +{ + [coder encodeValueOfObjCType: @encode(unsigned) at: &_refCount]; + [coder encodeValueOfObjCType: @encode(unsigned char[]) at: _bytes]; +} + +- (id)initWithCoder: (NSCoder *)coder +{ + self = [super init]; + + [coder decodeValueOfObjCType: @encode(unsigned) at: &_refCount]; + [coder decodeValueOfObjCType: @encode(unsigned char[]) at: _bytes]; + + return self; +} + +- (id)copyWithZone: (NSZone *)zone +{ + EOTemporaryGlobalID *gid = [super copyWithZone:zone]; + + gid->_refCount = _refCount; + memcpy(gid->_bytes, _bytes, sizeof(_bytes)); + + return gid; +} + +@end diff --git a/EOControl/EOKeyComparisonQualifier.m b/EOControl/EOKeyComparisonQualifier.m new file mode 100644 index 0000000..0dfefe7 --- /dev/null +++ b/EOControl/EOKeyComparisonQualifier.m @@ -0,0 +1,171 @@ +/** + EOKeyComparisonQualifier.m EOKeyComparisonQualifier + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import +#import + +#import +#import +#import + +#import + + +@implementation EOKeyComparisonQualifier + ++ (EOQualifier *)qualifierWithLeftKey: (NSString *)leftKey + operatorSelector: (SEL)selector + rightKey: (id)rightKey +{ + return [[[self alloc] initWithLeftKey: leftKey + operatorSelector: selector + rightKey: rightKey] autorelease]; +} + +- initWithLeftKey: (NSString *)leftKey + operatorSelector: (SEL)selector + rightKey: (id)rightKey +{ + if ((self = [super init])) + { + _selector = selector; + ASSIGN(_leftKey, leftKey); + ASSIGN(_rightKey, rightKey); + } + + return self; +} + +- (void)dealloc +{ + DESTROY(_leftKey); + DESTROY(_rightKey); + + [super dealloc]; +} + +- (SEL)selector +{ + return _selector; +} + +- (NSString *)leftKey +{ + return _leftKey; +} + +- (NSString *)rightKey +{ + return _rightKey; +} + +- (id)copyWithZone: (NSZone *)zone +{ + EOKeyComparisonQualifier *qual = [[EOKeyComparisonQualifier + allocWithZone: zone] init]; + + qual->_selector = _selector; + qual->_leftKey = [_leftKey copyWithZone: zone]; + qual->_rightKey = [_rightKey copyWithZone: zone]; + + return qual; +} + +- (BOOL)evaluateWithObject: (id)object +{ + id leftKey, rightKey; + + leftKey = [object valueForKey: _leftKey]; + rightKey = [object valueForKey: _rightKey]; + + if (sel_eq(_selector, EOQualifierOperatorEqual) == YES) + { + return [leftKey isEqual: rightKey] == NSOrderedSame; + } + else if (sel_eq(_selector, EOQualifierOperatorNotEqual) == YES) + { + return [leftKey isEqual: rightKey] != NSOrderedSame; + } + else if (sel_eq(_selector, EOQualifierOperatorLessThan) == YES) + { + return [leftKey compare: rightKey] == NSOrderedAscending; + } + else if (sel_eq(_selector, EOQualifierOperatorGreaterThan) == YES) + { + return [leftKey compare: rightKey] == NSOrderedDescending; + } + else if (sel_eq(_selector, EOQualifierOperatorLessThanOrEqualTo) == YES) + { + return [leftKey compare: rightKey] != NSOrderedDescending; + } + else if (sel_eq(_selector, EOQualifierOperatorGreaterThanOrEqualTo) == YES) + { + return [leftKey compare: rightKey] != NSOrderedAscending; + } + else if (sel_eq(_selector, EOQualifierOperatorContains) == YES) + { + [self notImplemented: _cmd]; + + return NO; + } + else if (sel_eq(_selector, EOQualifierOperatorLike) == YES) + { + NSEmitTODO(); //TODO + return [leftKey isEqual: rightKey] + == NSOrderedSame; + } + else if (sel_eq(_selector, EOQualifierOperatorCaseInsensitiveLike) == YES) + { + NSEmitTODO(); //TODO + return [[leftKey uppercaseString] isEqual: [rightKey uppercaseString]] + == NSOrderedSame; + } + + return NO; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%s %p - %@ %@ %@>", + object_get_class_name(self), + (void*)self, + _leftKey, + [isa stringForOperatorSelector:_selector], + _rightKey]; +} + +@end + diff --git a/EOControl/EOKeyGlobalID.h b/EOControl/EOKeyGlobalID.h new file mode 100644 index 0000000..1d0650e --- /dev/null +++ b/EOControl/EOKeyGlobalID.h @@ -0,0 +1,63 @@ +/* + EOKeyGlobalID.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: June 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOKeyGlobalID_h__ +#define __EOKeyGlobalID_h__ + +#import + +@interface EOKeyGlobalID : EOGlobalID +{ + unsigned short _keyCount; + NSString *_entityName; + id *_keyValues; +} + ++ (id)globalIDWithEntityName: (NSString *)entityName + keys: (id *)keys + keyCount: (unsigned)count + zone: (NSZone *)zone; + +- (NSString *)entityName; + +- (id *)keyValues; + +- (unsigned)keyCount; +- (NSArray *)keyValuesArray; + +- (BOOL)isEqual: other; +- (unsigned)hash; + +- (void)encodeWithCoder: (NSCoder *)aCoder; +- (id)initWithCoder: (NSCoder *)aDecoder; + +- (BOOL) isFinal; +- (NSString*)description; +- (BOOL)areKeysAllNulls; + +@end + +#endif diff --git a/EOControl/EOKeyGlobalID.m b/EOControl/EOKeyGlobalID.m new file mode 100644 index 0000000..49dc072 --- /dev/null +++ b/EOControl/EOKeyGlobalID.m @@ -0,0 +1,221 @@ +/** + EOKeyGlobalID.m EOKeyGlobalID Class + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: June 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import +#import + + +@implementation EOKeyGlobalID + ++ (id)globalIDWithEntityName: (NSString *)entityName + keys: (id *)keys + keyCount: (unsigned)count + zone: (NSZone *)zone +{ + EOKeyGlobalID *gid = [[[EOKeyGlobalID allocWithZone: zone] init] + autorelease]; + int i; + + ASSIGN(gid->_entityName, entityName); + gid->_keyCount = count; + + gid->_keyValues = NSZoneMalloc(zone, count * sizeof(id)); + + for (i = 0; i < count; i++) + { + gid->_keyValues[i] = nil; + ASSIGN(gid->_keyValues[i], keys[i]); + } + + if ([gid areKeysAllNulls]) + NSWarnLog(@"All key of globalID %p (%@) are nulls", + gid, + gid); + + return gid; +} + +- (void)dealloc +{ + int i; + + for (i = 0; i < _keyCount; i++) + DESTROY(_keyValues[i]); + + NSZoneFree(NULL, _keyValues); + + DESTROY(_entityName); + + [super dealloc]; +} + +- (NSString *)entityName +{ + return _entityName; +} + +- (id *)keyValues +{ + return _keyValues; +} + +- (unsigned)keyCount +{ + return _keyCount; +} + +- (NSArray *)keyValuesArray +{ + return [NSArray arrayWithObjects: _keyValues count: _keyCount]; +} + +- (BOOL)isEqual: other +{ + unsigned short oCount; + int i; + id *oValues; + + if (self == other) + return YES; + + if ([self hash] != [other hash]) + return NO; + + if ([_entityName isEqualToString: [other entityName]] == NO) + return NO; + + oCount = [other keyCount]; + oValues = [other keyValues]; + + for (i = 0; i < oCount; i++) + if ([_keyValues[i] isEqual: oValues[i]] == NO) + return NO; + + return YES; +} + + +- (unsigned int)hash // TODO +{ + int i; + unsigned int hash = 0; + + for (i = 0; i < _keyCount; i++) + hash += [_keyValues[i] hash]; + + hash += [_entityName hash]; + + return hash; +} + +- (void)encodeWithCoder: (NSCoder *)coder +{ + [coder encodeValueOfObjCType: @encode(unsigned short) at: &_keyCount]; + [coder encodeObject: _entityName]; + [coder encodeArrayOfObjCType: @encode(id) count: _keyCount at: _keyValues]; +} + +- (id)initWithCoder: (NSCoder *)coder +{ + self = [super init]; + + [coder decodeValueOfObjCType: @encode(unsigned short) at: &_keyCount]; + _entityName = [[coder decodeObject] retain]; + + _keyValues = NSZoneMalloc([coder objectZone], _keyCount); + [coder decodeArrayOfObjCType: @encode(id) count: _keyCount at: _keyValues]; + + return self; +} + +- (id)copyWithZone: (NSZone *)zone +{ + EOKeyGlobalID *gid = [super copyWithZone: zone]; + int i; + + ASSIGN(gid->_entityName, _entityName); + gid->_keyCount = _keyCount; + + gid->_keyValues = NSZoneMalloc(zone, _keyCount * sizeof(id)); + + for (i = 0; i < _keyCount; i++) + { + gid->_keyValues[i] = nil; + ASSIGN(gid->_keyValues[i], _keyValues[i]); + } + + return gid; +} + +- (BOOL) isFinal +{ +// [self notImplemented:_cmd]; //TODO + return YES; +} + +- (NSString*)description +{ + NSString *dscr; + int i; + + dscr = [NSString stringWithFormat: @"<%s %p - Entity %@ - keysValues:", + object_get_class_name(self), + (void*)self, + _entityName]; + + for(i = 0; i < _keyCount; i++) + { + dscr = [dscr stringByAppendingFormat: @"\"%@\" (%@) ", + _keyValues[i], + [_keyValues[i] class]]; + } + dscr = [dscr stringByAppendingString: @">"]; + + return dscr; +} + +-(BOOL)areKeysAllNulls +{ + int i; + BOOL areNulls = YES; + + for (i = 0; areNulls && i < _keyCount; i++) + areNulls = isNilOrEONull(_keyValues[i]); + + return areNulls; +} + +@end diff --git a/EOControl/EOKeyValueArchiver.h b/EOControl/EOKeyValueArchiver.h new file mode 100644 index 0000000..a78f25e --- /dev/null +++ b/EOControl/EOKeyValueArchiver.h @@ -0,0 +1,142 @@ +/* + EOKeyValueArchiver.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOKeyValueArchiving_h__ +#define __EOKeyValueArchiving_h__ + + +#import + +@interface EOKeyValueArchiver : NSObject +{ + NSMutableDictionary *_propertyList; + id _delegate; +} + +- (id) init; + +- (void)dealloc; + +- (void)encodeObject: (id)object + forKey: (NSString *)key; + +- (void)encodeReferenceToObject: (id)object + forKey: (NSString *)key; + +- (void)encodeBool: (BOOL)yn + forKey: (NSString *)key; + +- (void)encodeInt: (int)intValue + forKey: (NSString *)key; + +- (void) _encodeDictionary: (id)dictionary + forKey: (id)key; +- (void) _encodeObjects: (id)objects + forKey: (id)key; +- (void) _encodeValue: (id)value + forKey: (id)key; + +- (NSDictionary *)dictionary; + +- (void)setDelegate: (id)delegate; +- (id)delegate; + +@end + + +@interface NSObject (EOKeyValueArchiverDelegation) + +- (id)archiver: (EOKeyValueArchiver *)archiver +referenceToEncodeForObject: (id)object; + +@end + + +@interface EOKeyValueUnarchiver : NSObject +{ + NSDictionary* _propertyList; + id _parent; + id _nextParent; + NSMutableArray* _allUnarchivedObjects; + id _delegate; + NSHashTable* _awakenedObjects; +} + +- (id)initWithDictionary: (NSDictionary *)dictionary; + +- (id)decodeObjectForKey: (NSString *)key; + +- (id)decodeObjectReferenceForKey: (NSString *)key; + +- (BOOL)decodeBoolForKey: (NSString *)key; + +- (int)decodeIntForKey: (NSString *)key; + +- (BOOL) isThereValueForKey: (NSString *)key; + +- (void)ensureObjectAwake: (id)object; + +- (void)finishInitializationOfObjects; + +- (void)awakeObjects; + +- (id)parent; + +- (void)setDelegate: (id)delegate; +- (id)delegate; + +- (id) _findTypeForPropertyListDecoding: (id)param0; +- (id) _dictionaryForPropertyList: (NSDictionary*)propList; +- (id) _objectsForPropertyList: (NSArray*)propList; +- (id) _objectForPropertyList: (NSDictionary*)propList; + +@end + +@interface NSObject (EOKeyValueUnarchiverDelegation) + +- (id)unarchiver: (EOKeyValueUnarchiver *)archiver +objectForReference: (id)keyPath; + +@end + +@protocol EOKeyValueArchiving + +- (id) initWithKeyValueUnarchiver: (EOKeyValueUnarchiver *)unarchiver; + +- (void)encodeWithKeyValueArchiver: (EOKeyValueArchiver *)archiver; + +@end + +@interface NSObject(EOKeyValueArchivingAwakeMethods) + +- (void)finishInitializationWithKeyValueUnarchiver: (EOKeyValueUnarchiver *)unarchiver; + +- (void)awakeFromKeyValueUnarchiver: (EOKeyValueUnarchiver *)unarchiver; + +@end + + +#endif diff --git a/EOControl/EOKeyValueArchiver.m b/EOControl/EOKeyValueArchiver.m new file mode 100644 index 0000000..0a45c8c --- /dev/null +++ b/EOControl/EOKeyValueArchiver.m @@ -0,0 +1,766 @@ +/** + EOKeyValueArchiver.m EOKeyValueArchiver Class + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: September 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import +#import + + +@interface EOKeyValueArchivingContainer : NSObject +{ + id _object; + id _parent; + NSDictionary * _propertyList; +} + ++ (EOKeyValueArchivingContainer*)keyValueArchivingContainer; +- (void) setPropertyList: (id)propList; +- (id) propertyList; +- (void) setParent: (id)parent; +- (id) parent; +- (void) setObject: (id)object; +- (id) object; +- (void) dealloc; + +@end + + +@implementation EOKeyValueArchivingContainer + ++ (EOKeyValueArchivingContainer *)keyValueArchivingContainer +{ + return [[[self alloc] init] autorelease]; +} + +- (void) setPropertyList: (id)propList +{ + ASSIGN(_propertyList, propList); +} + +- (id) propertyList +{ + return _propertyList; +} + +- (void) setParent: (id)parent +{ + _parent = parent; +} + +- (id) parent +{ + return _parent; +} + +- (void) setObject: (id)object +{ + ASSIGN(_object, object); +} + +- (id) object +{ + return _object; +} + +- (void) dealloc +{ + DESTROY(_object); + _parent = nil; + DESTROY(_propertyList); + + [super dealloc]; +} + +@end + + +@implementation EOKeyValueArchiver + +- (id) init +{ + [self notImplemented: _cmd]; //TODOFN + return nil; +} + +- (void) dealloc +{ + DESTROY(_propertyList); + [super dealloc]; +} + +- (id) dictionary +{ + return _propertyList; +} + +- (void) encodeInt: (int)intValue + forKey: (NSString*)key +{ + [self notImplemented: _cmd]; //TODOFN +} + +- (void) encodeBool: (BOOL)yn + forKey: (NSString*)key +{ + [self notImplemented: _cmd]; //TODOFN +} + +- (void) encodeReferenceToObject: (id)object + forKey: (NSString*)key +{ + [self notImplemented: _cmd]; //TODOFN +} + +- (void) encodeObject: (id)object + forKey: (NSString*)key +{ + [self notImplemented: _cmd]; //TODOFN +} + +- (void) _encodeDictionary: (id)dictionary + forKey: (NSString*)key +{ + [self notImplemented: _cmd]; //TODOFN +} + +- (void) _encodeObjects: (id)objects + forKey: (NSString*)key +{ + [self notImplemented: _cmd]; //TODOFN +} + +- (void) _encodeValue: (id)value + forKey: (NSString*)key +{ + [self notImplemented: _cmd]; //TODOFN +} + +- (id) delegate +{ + return _delegate; +} + +- (void) setDelegate: (id)delegate +{ + _delegate=delegate; +} + +@end + + +@implementation NSObject (EOKeyValueArchiverDelegation) + +- (id)archiver: (EOKeyValueArchiver *)archiver +referenceToEncodeForObject: (id)object +{ + [self notImplemented: _cmd]; //TODOFN + return nil; +} + +@end + + +@implementation EOKeyValueUnarchiver + +- (id) initWithDictionary: (NSDictionary*)dictionary +{ + if ((self = [super init])) + { + ASSIGN(_propertyList, dictionary); + _allUnarchivedObjects = [NSMutableArray array]; + + RETAIN(_allUnarchivedObjects); + } + + return self; +} + +- (void) finishInitializationOfObjects +{ + int i; + int count = [_allUnarchivedObjects count]; + + for (i = 0; i < count; i++) + { + EOKeyValueArchivingContainer *container; + id object; + + container = [_allUnarchivedObjects objectAtIndex: i]; + object = [container object]; + + NSDebugMLLog(@"gsdb", @"finishInitializationWithKeyValueUnarchiver index:%d", i); + + [object finishInitializationWithKeyValueUnarchiver: self]; + } +} + +- (void) dealloc +{ + DESTROY(_propertyList); + DESTROY(_allUnarchivedObjects); + + if (_awakenedObjects) + NSFreeHashTable(_awakenedObjects); + + [super dealloc]; +} + +- (void) awakeObjects +{ + int i; + int count = [_allUnarchivedObjects count]; + + if (!_awakenedObjects) + _awakenedObjects = NSCreateHashTable(NSNonRetainedObjectHashCallBacks, + count); + + for (i = 0; i < count; i++) + { + EOKeyValueArchivingContainer *container; + id object; + + NSDebugMLLog(@"gsdb", @"awakeObject index:%d", i); + + container = [_allUnarchivedObjects objectAtIndex: i]; + object = [container object]; + + [self ensureObjectAwake:object]; + } +} + +- (void) ensureObjectAwake: (id)object +{ + if (object) + { + if (!NSHashInsertIfAbsent(_awakenedObjects, object)) + { + NSDebugMLLog(@"gsdb", @"ensureObjectAwake:%@", object); + + [object awakeFromKeyValueUnarchiver: self]; + } + } +} + +- (int) decodeIntForKey: (NSString*)key +{ + id object; + + NSDebugMLLog(@"gsdb", @"decodeIntForKey:%@", key); + + object = [_propertyList objectForKey: key]; + + return [object intValue]; +} + +- (BOOL) decodeBoolForKey: (NSString*)key +{ + id object; + + NSDebugMLLog(@"gsdb", @"decodeBoolForKey:%@", key); + + object = [_propertyList objectForKey: key]; + + return [[_propertyList objectForKey: key] boolValue]; +} + +- (id) decodeObjectReferenceForKey: (NSString*)key +{ + id objectReference = nil; + id object; + + NSDebugMLLog(@"gsdb", @"decodeObjectReferenceForKey:%@", key); + + object = [self decodeObjectForKey: key]; + + if (object) + { + objectReference = [_delegate unarchiver: self + objectForReference: object]; + } + + return objectReference; +} + +- (id) decodeObjectForKey: (NSString*)key +{ + id propListObject; + id obj = nil; + + NSDebugMLLog(@"gsdb", @"decodeObjectForKey:%@", key); + + propListObject = [_propertyList objectForKey: key]; + NSDebugMLLog(@"gsdb", @"key: %@ propListObject:%@", key, propListObject); + + if (propListObject) + { + obj = [self _findTypeForPropertyListDecoding: propListObject]; + } + + NSDebugMLLog(@"gsdb", @"key: %@ obj:%@", key, obj); + + return obj; +} + +- (BOOL) isThereValueForKey: (NSString *)key +{ + return ([_propertyList objectForKey: key] != nil); +} + +- (id) _findTypeForPropertyListDecoding: (id)obj +{ + id retVal = nil; + + NSDebugMLLog(@"gsdb", @"obj:%@", obj); + + if ([obj isKindOfClass: [NSDictionary class]]) + { + NSString *className = [obj objectForKey: @"class"]; + + if (className) + retVal = [self _objectForPropertyList: obj]; + else + retVal = [self _dictionaryForPropertyList: obj]; + + if (!retVal) + { + //TODO + NSDebugMLLog(@"gsdb", @"ERROR: No retVal for Obj:%@", obj); + } + } + else if ([obj isKindOfClass: [NSArray class]]) + retVal = [self _objectsForPropertyList: obj]; + else + retVal=obj; + + NSDebugMLLog(@"gsdb", @"retVal:%@", retVal); + + return retVal; + /* + { + batchSize = {AutoInitialized = 1; TypeName = Object; }; + checkOutLength = {AutoInitialized = 1; TypeName = Object; }; + cost = {AutoInitialized = 1; TypeName = Object; }; + currentItem = {TypeName = Object; }; + dateAcquired = {AutoInitialized = 1; TypeName = Object; }; + discInsert = {TypeName = Object; }; + errorString = {AutoInitialized = 1; TypeName = Object; }; + media = {AutoInitialized = 1; TypeName = Object; }; + movieMedia = {TypeName = MovieMedia; }; + movieMediaDataSource = {TypeName = Object; }; + moviemedias = { + AutoInitialized = 1; + TypeName = MovieMedias; + initialValue = { + class = WODisplayGroup; + dataSource = { + class = EODatabaseDataSource; + editingContext = session.defaultEditingContext; + fetchSpecification = {class = EOFetchSpecification; entityName = MovieMedia; isDeep = YES; }; + }; + formatForLikeQualifier = "%@*"; + numberOfObjectsPerBatch = 10; + selectsFirstObjectAfterFetch = YES; + }; + }; + objectArray = {TypeName = Object; }; + ordering = {AutoInitialized = 1; TypeName = Object; }; + orderingsArray = {AutoInitialized = 1; TypeName = Object; }; + rentalType = {AutoInitialized = 1; TypeName = Object; }; + selectedOrderings = {AutoInitialized = 1; TypeName = Object; }; + tapeInsert = {TypeName = Object; }; + yes = {TypeName = Object; }; + } + [self _dictionaryForPropertyList:param0]; + + //2 + {TypeName = Object; } + _dictionaryForPropertyList:{TypeName = Object; } + + + + //4 + Object + return Object + + //5 [2] + return {TypeName = Object; } + + + + + // A1 + Description: { + AutoInitialized = 1; + TypeName = MovieMedias; + initialValue = { + class = WODisplayGroup; + dataSource = { + class = EODatabaseDataSource; + editingContext = session.defaultEditingContext; + fetchSpecification = {class = EOFetchSpecification; entityName = MovieMedia; isDeep = YES; }; + }; + formatForLikeQualifier = "%@*"; + numberOfObjectsPerBatch = 10; + selectsFirstObjectAfterFetch = YES; + }; + } + _dictionaryForPropertyList: + + //A 4 + _objectForPropertyList: + Description: { + class = WODisplayGroup; + dataSource = { + class = EODatabaseDataSource; + editingContext = session.defaultEditingContext; + fetchSpecification = {class = EOFetchSpecification; entityName = MovieMedia; isDeep = YES; }; + }; + formatForLikeQualifier = "%@*"; + numberOfObjectsPerBatch = 10; + selectsFirstObjectAfterFetch = YES; + } + + + + //B1 + Description: { + class = EODatabaseDataSource; + editingContext = session.defaultEditingContext; + fetchSpecification = {class = EOFetchSpecification; entityName = MovieMedia; isDeep = YES; }; + } + + _objectForPropertyList:object + Description: { + class = EODatabaseDataSource; + editingContext = session.defaultEditingContext; + fetchSpecification = {class = EOFetchSpecification; entityName = MovieMedia; isDeep = YES; }; + } + + + return _objectForPropertyList:obj; EOFetchSpecification + + + _objectForPropertyList:{ + class = WODisplayGroup; + dataSource = { + class = EODatabaseDataSource; + editingContext = session.defaultEditingContext; + fetchSpecification = {class = EOFetchSpecification; entityName = MovieMedia; isDeep = YES; }; + }; + formatForLikeQualifier = "%@*"; + numberOfObjectsPerBatch = 10; + selectsFirstObjectAfterFetch = YES; + } + */ +} + +- (id) _dictionaryForPropertyList: (NSDictionary*)propList +{ + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + NSEnumerator *enumerator = [propList keyEnumerator]; + id key; + + while ((key = [enumerator nextObject])) + { + id object; + id retObject; + + NSDebugMLLog(@"gsdb", @"key:%@", key); + + object = [propList objectForKey: key]; + NSDebugMLLog(@"gsdb", @"Object:%@", object); + + retObject = [self _findTypeForPropertyListDecoding: object]; + NSDebugMLLog(@"gsdb", @"retObject:%@", retObject); + + if (!retObject) + { + NSDebugMLLog(@"gsdb", @"ERROR: No retObject for Object:%@", object); + //TODO + } + else + [dict setObject: retObject + forKey: key]; + } + + return dict; +} + +/* +{ + batchSize = {AutoInitialized = 1; TypeName = Object; }; + checkOutLength = {AutoInitialized = 1; TypeName = Object; }; + cost = {AutoInitialized = 1; TypeName = Object; }; + currentItem = {TypeName = Object; }; + dateAcquired = {AutoInitialized = 1; TypeName = Object; }; + discInsert = {TypeName = Object; }; + errorString = {AutoInitialized = 1; TypeName = Object; }; + media = {AutoInitialized = 1; TypeName = Object; }; + movieMedia = {TypeName = MovieMedia; }; + movieMediaDataSource = {TypeName = Object; }; + moviemedias = { + AutoInitialized = 1; + TypeName = MovieMedias; + initialValue = { + class = WODisplayGroup; + dataSource = { + class = EODatabaseDataSource; + editingContext = session.defaultEditingContext; + fetchSpecification = {class = EOFetchSpecification; entityName = MovieMedia; isDeep = YES; }; + }; + formatForLikeQualifier = "%@*"; + numberOfObjectsPerBatch = 10; + selectsFirstObjectAfterFetch = YES; + }; + }; + objectArray = {TypeName = Object; }; + ordering = {AutoInitialized = 1; TypeName = Object; }; + orderingsArray = {AutoInitialized = 1; TypeName = Object; }; + rentalType = {AutoInitialized = 1; TypeName = Object; }; + selectedOrderings = {AutoInitialized = 1; TypeName = Object; }; + tapeInsert = {TypeName = Object; }; + yes = {TypeName = Object; }; +} + + _findTypeForPropertyListDecoding:{TypeName = Object; } + + +//3 +{TypeName = Object; } +_findTypeForPropertyListDecoding:Object +(return Object) +return {TypeName = Object; } <== + +//6 [1] +{TypeName = Object; } + +_findTypeForPropertyListDecoding:{TypeName = MovieMedia; } + + + +//A2 + object= + Description: { + AutoInitialized = 1; + TypeName = MovieMedias; + initialValue = { + class = WODisplayGroup; + dataSource = { + class = EODatabaseDataSource; + editingContext = session.defaultEditingContext; + fetchSpecification = {class = EOFetchSpecification; entityName = MovieMedia; isDeep = YES; }; + }; + formatForLikeQualifier = "%@*"; + numberOfObjectsPerBatch = 10; + selectsFirstObjectAfterFetch = YES; + }; +} + +_findTypeForPropertyListDecoding:object= + Description: 1 +_findTypeForPropertyListDecoding + Description: MovieMedias +_findTypeForPropertyListDecoding:object= + Description: { + class = WODisplayGroup; + dataSource = { + class = EODatabaseDataSource; + editingContext = session.defaultEditingContext; + fetchSpecification = {class = EOFetchSpecification; entityName = MovieMedia; isDeep = YES; }; + }; + formatForLikeQualifier = "%@*"; + numberOfObjectsPerBatch = 10; + selectsFirstObjectAfterFetch = YES; +} +*/ + +- (id) _objectsForPropertyList: (NSArray*)propList +{ + NSMutableArray *newObjects = [NSMutableArray array]; + id object = nil; + NSEnumerator *propListEnum; + id propListObject; + + EOFLOGObjectFnStartOrCond(@"EOKeyValueUnarchiver"); + + if (propList && (propListEnum = [propList objectEnumerator])) + { + while ((propListObject = [propListEnum nextObject])) + { + object = [self _findTypeForPropertyListDecoding: propListObject]; + + if (object) + { + [newObjects addObject: object]; + } + } + } + + EOFLOGObjectFnStopOrCond(@"EOKeyValueUnarchiver"); + + return newObjects; +} + +- (id) _objectForPropertyList: (NSDictionary*)propList +{ + EOKeyValueArchivingContainer *container = nil; + NSString *className = nil; + Class objectClass = Nil; + id object = nil; + NSDictionary *oldPropList = AUTORELEASE(_propertyList); + + _propertyList = RETAIN(propList); //Because dealloc may try to release it + + NSDebugMLLog(@"gsdb", @"propList:%@", propList); + + NS_DURING + { + className = [propList objectForKey: @"class"]; + objectClass = NSClassFromString(className); + + NSAssert1(objectClass, @"ERROR: No class named '%@'", className); + + object = [[[objectClass alloc] initWithKeyValueUnarchiver: self] + autorelease]; + container = [EOKeyValueArchivingContainer keyValueArchivingContainer]; + + [container setObject: object]; + [container setParent: nil]; //TODO VERIFY + [container setPropertyList: propList]; + + [_allUnarchivedObjects addObject: container]; + } + NS_HANDLER + { + NSDebugMLLog(@"gsdb", @"EOKeyValueUnarchiver",@"EXCEPTION:%@ (%@) [%s %d]", + localException, + [localException reason], + __FILE__, + __LINE__); + + //Restaure the original propertyList + _propertyList = RETAIN(oldPropList); + + AUTORELEASE(propList); + [localException raise]; + } + NS_ENDHANDLER; + + _propertyList = RETAIN(oldPropList); + + AUTORELEASE(propList); + + NSDebugMLLog(@"gsdb", @"propList:%@", propList); + NSDebugMLLog(@"gsdb", @"object:%@", object); + + return object; +} +/* + //EOFetchSpecification + + prop{ + class = WODisplayGroup; + dataSource = { + class = EODatabaseDataSource; + editingContext = session.defaultEditingContext; + fetchSpecification = {class = EOFetchSpecification; entityName = MovieMedia; isDeep = YES; }; + }; + formatForLikeQualifier = "%@*"; + numberOfObjectsPerBatch = 10; + selectsFirstObjectAfterFetch = YES; + }] + + + + + object= + Description: { + class = WODisplayGroup; + dataSource = { + class = EODatabaseDataSource; + editingContext = session.defaultEditingContext; + fetchSpecification = {class = EOFetchSpecification; entityName = MovieMedia; isDeep = YES; }; + }; + formatForLikeQualifier = "%@*"; + numberOfObjectsPerBatch = 10; + selectsFirstObjectAfterFetch = YES; + } + + +*/ + +- (id) parent +{ + return _parent; +} + +- (id) delegate +{ + return _delegate; +} + +- (void) setDelegate:(id)delegate +{ + _delegate=delegate; +} + +@end + + +@implementation NSObject (EOKeyValueUnarchiverDelegation) + +- (id)unarchiver: (EOKeyValueUnarchiver*)archiver +objectForReference: (id)keyPath +{ + [self notImplemented: _cmd]; //TODOFN + return nil; +} + +@end + + +@implementation NSObject(EOKeyValueArchivingAwakeMethods) + +- (void)finishInitializationWithKeyValueUnarchiver: (EOKeyValueUnarchiver *)unarchiver +{ + //Does nothing ? +} + +- (void)awakeFromKeyValueUnarchiver: (EOKeyValueUnarchiver *)unarchiver; +{ + //Does nothing ? +} + +@end diff --git a/EOControl/EOKeyValueCoding.h b/EOControl/EOKeyValueCoding.h new file mode 100644 index 0000000..682726b --- /dev/null +++ b/EOControl/EOKeyValueCoding.h @@ -0,0 +1,75 @@ +/* + EOKeyValueCoding.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOKeyValueCoding_h__ +#define __EOKeyValueCoding_h__ + +#import +#import +#import + +#import + + +@class NSDictionary; + + +@interface NSObject (EOKVCPAdditions2) +- (void)takeStoredValue: value + forKeyPath: (NSString *)key; +- (void)takeStoredValuesFromDictionary: (NSDictionary *)dictionary; +- (NSDictionary *)valuesForKeyPaths: (NSArray *)keyPaths; +@end + + +@interface NSArray (EOKeyValueCoding) +- (id)valueForKey: (NSString *)key; +- (id)valueForKeyPath: (NSString *)keyPath; +- (id)computeSumForKey: (NSString *)key; +- (id)computeAvgForKey: (NSString *)key; +- (id)computeCountForKey: (NSString *)key; +- (id)computeMaxForKey: (NSString *)key; +- (id)computeMinForKey: (NSString *)key; +@end + + + + +@interface NSDictionary (EOKeyValueCoding) +- (id)valueForKey: (NSString *)key; +@end + + +@interface NSMutableDictionary (EOKeyValueCoding) +- (void)takeValue: (id)value + forKey: (NSString*)key; +@end + +extern NSString *EOUnknownKeyException; +extern NSString *EOTargetObjectUserInfoKey; +extern NSString *EOUnknownUserInfoKey; + +#endif /* __EOKeyValueCoding_h__ */ diff --git a/EOControl/EOKeyValueCoding.m b/EOControl/EOKeyValueCoding.m new file mode 100644 index 0000000..3868f1e --- /dev/null +++ b/EOControl/EOKeyValueCoding.m @@ -0,0 +1,985 @@ +/** + EOKeyValueCoding.m EOKeyValueCoding + + Copyright (C) 1996-2002 Free Software Foundation, Inc. + + Author: Mircea Oancea + Date: November 1996 + + Author: Mirko Viviani + Date: February 2000 + + Author: Manuel Guesdon + Date: January 2002 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#import +#import +#import + +#import +#import +#import +#import + + +/* + * EOKeyValueCodingAdditions implementation + */ + +@implementation NSObject (EOKVCPAdditions2) + +/** if key is a bidirectional rel, use addObject:toBothSidesOfRelationship otherwise call takeValue:forKey: **/ +- (void)smartTakeValue: (id)anObject + forKey: (NSString *)aKey +{ + [self takeValue: anObject + forKey: aKey]; +} + +- (void)smartTakeValue: (id)anObject + forKeyPath: (NSString *)aKeyPath +{ + NSRange r = [aKeyPath rangeOfString: @"."]; + + if (r.length == 0) + { + [self smartTakeValue: anObject + forKey: aKeyPath]; + } + else + { + NSString *key = [aKeyPath substringToIndex: r.location]; + NSString *path = [aKeyPath substringFromIndex: NSMaxRange(r)]; + + [[self valueForKey: key] smartTakeValue: anObject + forKeyPath: path]; + } +} + +- (void)takeStoredValue: value + forKeyPath: (NSString *)key +{ + NSArray *pathArray; + NSString *path; + id obj = self; + int i, count; + + EOFLOGObjectFnStartCond(@"EOKVC"); + + pathArray = [key componentsSeparatedByString:@"."]; + count = [pathArray count]; + + for (i = 0; i < (count - 1); i++) + { + path = [pathArray objectAtIndex: i]; + obj = [obj valueForKey: path]; + } + + path = [pathArray lastObject]; + [obj takeStoredValue: value forKey: path]; + + EOFLOGObjectFnStopCond(@"EOKVC"); +} + +- (id)storedValueForKeyPath: (NSString *)key +{ + NSArray *pathArray = nil; + NSString *path; + id obj = self; + int i, count; + EOFLOGObjectFnStartCond(@"EOKVC"); + pathArray = [key componentsSeparatedByString:@"."]; + count = [pathArray count]; + + for(i=0; i < (count-1); i++) + { + path = [pathArray objectAtIndex:i]; + obj = [obj valueForKey:path]; + } + + path = [pathArray lastObject]; + obj=[obj storedValueForKey:path]; + EOFLOGObjectFnStopCond(@"EOKVC"); + return obj; +} + +- (void)takeStoredValuesFromDictionary: (NSDictionary *)dictionary +{ + NSEnumerator *keyEnum; + id key; + id val; + + EOFLOGObjectFnStartCond(@"EOKVC"); + + keyEnum = [dictionary keyEnumerator]; + + while ((key = [keyEnum nextObject])) + { + val = [dictionary objectForKey: key]; + + if ([val isKindOfClass: [[EONull null] class]]) + val = nil; + + [self takeStoredValue: val forKey: key]; + } + + EOFLOGObjectFnStopCond(@"EOKVC"); +} + +- (NSDictionary *)storedValuesForKeyPaths: (NSArray *)keyPaths +{ + NSDictionary *values = nil; + int i, n; + NSMutableArray *newKeyPaths = nil; + NSMutableArray *newVals = nil; + EONull *null; + + EOFLOGObjectFnStartCond(@"EOKVC"); + + n = [keyPaths count]; + + newKeyPaths = [[[NSMutableArray alloc] initWithCapacity: n] + autorelease]; + newVals = [[[NSMutableArray alloc] initWithCapacity: n] + autorelease]; + null = (EONull *)[EONull null]; + + for (i = 0; i < n; i++) + { + id keyPath = [keyPaths objectAtIndex: i]; + id val = nil; + + NS_DURING //DEBUG Only ? + { + val = [self storedValueForKeyPath: keyPath]; + } + NS_HANDLER + { + NSLog(@"EXCEPTION %@", localException); + NSDebugMLog(@"EXCEPTION %@", localException); + [localException raise]; + } + NS_ENDHANDLER; + + if (val == nil) + val = null; + + [newKeyPaths addObject: keyPath]; + [newVals addObject: val]; + } + + values = [NSDictionary dictionaryWithObjects: newVals + forKeys: newKeyPaths]; + EOFLOGObjectFnStopCond(@"EOKVC"); + + return values; +} + +- (NSDictionary *)valuesForKeyPaths: (NSArray *)keyPaths +{ + NSDictionary *values = nil; + int i; + int n; + NSMutableArray *newKeyPaths; + NSMutableArray *newVals; + EONull *null; + + EOFLOGObjectFnStartCond(@"EOKVC"); + + n = [keyPaths count]; + newKeyPaths = [[[NSMutableArray alloc] initWithCapacity: n] + autorelease]; + newVals = [[[NSMutableArray alloc] initWithCapacity: n] + autorelease]; + null = (EONull *)[EONull null]; + + for (i = 0; i < n; i++) + { + id keyPath = [keyPaths objectAtIndex: i]; + id val = nil; + + NS_DURING //DEBUG Only ? + { + val = [self valueForKeyPath: keyPath]; + } + NS_HANDLER + { + NSLog(@"EXCEPTION %@", localException); + NSDebugMLog(@"EXCEPTION %@",localException); + [localException raise]; + } + NS_ENDHANDLER; + + if (val == nil) + val = null; + + [newKeyPaths addObject: keyPath]; + [newVals addObject: val]; + } + + values = [NSDictionary dictionaryWithObjects: newVals + forKeys: newKeyPaths]; + + EOFLOGObjectFnStopCond(@"EOKVC"); + + return values; +} + +@end + +@implementation NSArray (EOKeyValueCoding) + +- (id)valueForKey: (NSString *)key +{ + id result = nil; + const char *str; + + EOFLOGObjectFnStartCond(@"EOKVC"); + //EOFLOGObjectLevelArgs(@"EOKVC", @"key=%@", + // key); + + str=[key cString]; + + if (str && *str == '@') + { + if ([key length] > 1) + { + if ([key isEqualToString: @"@count"]) //the only known case because we haven't implemented custom operators + result = [super valueForKey: @"count"]; + else // for unknwon case: call computeXXForKey:nil + { + NSMutableString *selString = [NSMutableString stringWithCapacity:10]; + SEL computeSelector; + char l = str[1]; + + if (islower(l)) + l = toupper(l); + + [selString appendString: @"compute"]; + [selString appendString: [NSString stringWithCString: &l + length: 1]]; + [selString appendString: [NSString stringWithCString: &str[2]]]; + [selString appendString: @"ForKey:"]; + + computeSelector = NSSelectorFromString(selString); + result = [self performSelector: computeSelector + withObject: nil]; + } + } + } + else if ([key isEqualToString: @"count"]) //Special case: Apple Doc is wrong; here we return -count + { + static BOOL warnedCount = NO; + if (warnedCount == NO) + { + warnedCount = YES; + NSWarnLog(@"use of special 'count' key may works differently with only foundation base"); + } + result = [super valueForKey: key]; + } + else + { + result = [self resultsOfPerformingSelector: @selector(valueForKey:) + withObject: key + defaultResult: [EONull null]]; + } + + EOFLOGObjectFnStopCond(@"EOKVC"); + + return result; +} + +- (id)valueForKeyPath: (NSString *)keyPath +{ + id result = nil; + const char *str; + + EOFLOGObjectFnStartCond(@"EOKVC"); + //EOFLOGObjectLevelArgs(@"EOKVC", @"keyPath=%@", + // keyPath); + + str = [keyPath cString]; + + if (str && *str == '@') + { + if ([keyPath length] > 1) + { + NSMutableString *selString = [NSMutableString stringWithCapacity: 10]; + NSArray *pathArray = [keyPath componentsSeparatedByString: @"."]; + + if ([pathArray count] == 1) + { + } + else + { + NSString* fn= [pathArray objectAtIndex:0]; + NSString* key=nil; + SEL computeSelector; + char l; + str=[fn cString]; + l = str[1]; + + if (islower(l)) + l = toupper(l); + + [selString appendString: @"compute"]; + [selString appendString: [NSString stringWithCString: &l + length: 1]]; + [selString appendString: [NSString stringWithCString: &str[2]]]; + [selString appendString: @"ForKey:"]; + + computeSelector = NSSelectorFromString(selString); + if ([pathArray count] > 1) + key = [pathArray objectAtIndex: 1]; + + result = [self performSelector: computeSelector + withObject: key]; + + if (result && [pathArray count] > 2) + { + NSArray *rightKeyPathArray + = [pathArray subarrayWithRange: + NSMakeRange(2, [pathArray count] - 2)]; + NSString *rightKeyPath + = [rightKeyPathArray componentsJoinedByString: @"."]; + + result = [result valueForKeyPath: rightKeyPath]; + } + } + } + } + else if ([keyPath isEqualToString: @"count"]) //Special case: Apple Doc is wrong; here we return -count + { + static BOOL warnedCount = NO; + if (warnedCount == NO) + { + warnedCount = YES; + NSWarnLog(@"use of special 'count' key may works differently with only foundation base"); + } + result = [super valueForKeyPath: keyPath]; + } + else + result = [self resultsOfPerformingSelector: @selector(valueForKeyPath:) + withObject: keyPath + defaultResult: [EONull null]]; + + EOFLOGObjectFnStopCond(@"EOKVC"); + + return result; +} + +- (id)computeSumForKey: (NSString *)key +{ + NSEnumerator *arrayEnum; + NSDecimalNumber *item, *ret; + + EOFLOGObjectFnStartCond(@"EOKVC"); + + arrayEnum = [self objectEnumerator]; + ret = [NSDecimalNumber zero]; + + while ((item = [arrayEnum nextObject])) + [ret decimalNumberByAdding: item]; + + EOFLOGObjectFnStopCond(@"EOKVC"); + + return ret; +} + +- (id)computeAvgForKey: (NSString *)key +{ + NSEnumerator *arrayEnum; + NSDecimalNumber *item, *ret; + + EOFLOGObjectFnStartCond(@"EOKVC"); + + arrayEnum = [self objectEnumerator]; + ret = [NSDecimalNumber zero]; + + while ((item = [arrayEnum nextObject])) + [ret decimalNumberByAdding: item]; + + ret = [ret decimalNumberByDividingBy: + [NSDecimalNumber decimalNumberWithMantissa: [self count] + exponent: 0 + isNegative:NO]]; + + EOFLOGObjectFnStopCond(@"EOKVC"); + + return ret; +} + +- (id)computeCountForKey: (NSString *)key +{ + id ret; + + EOFLOGObjectFnStartCond(@"EOKVC"); + + ret = [NSNumber numberWithInt: [self count]]; + + EOFLOGObjectFnStopCond(@"EOKVC"); + + return ret; +} + +- (id)computeMaxForKey: (NSString *)key +{ + NSEnumerator *arrayEnum; + NSDecimalNumber *item, *max; + + EOFLOGObjectFnStartCond(@"EOKVC"); + + arrayEnum = [self objectEnumerator]; + + max = item = [arrayEnum nextObject]; + + if (max != nil) + { + while ((item = [arrayEnum nextObject])) + { + if ([max compare: item] == NSOrderedAscending) + max = item; + } + } + + EOFLOGObjectFnStopCond(@"EOKVC"); + + return max; +} + +- (id)computeMinForKey: (NSString *)key +{ + NSEnumerator *arrayEnum; + NSDecimalNumber *item, *min; + + EOFLOGObjectFnStartCond(@"EOKVC"); + + arrayEnum = [self objectEnumerator]; + min = item = [arrayEnum nextObject]; + + if (min != nil) + { + while ((item = [arrayEnum nextObject])) + { + if ([min compare: item] == NSOrderedDescending) + min = item; + } + } + + EOFLOGObjectFnStopCond(@"EOKVC"); + + return min; +} + +@end + + +@implementation NSDictionary (EOKeyValueCoding) + +- (id)valueForKey:(NSString *)key +{ + id value; + + EOFLOGObjectFnStartCond(@"EOKVC"); + EOFLOGObjectLevelArgs(@"EOKVC", @"key=%@", + key); + + value = [self objectForKey: key]; + + if (!value) + { + if ([key isEqualToString: @"allValues"]) + { + static BOOL warnedAllValues = NO; + if (warnedAllValues == NO) + { + warnedAllValues = YES; + NSWarnLog(@"use of special 'allValues' key works differently with only foundation base"); + } + + value = [self allValues]; + } + else if ([key isEqualToString: @"allKeys"]) + { + static BOOL warnedAllKeys = NO; + if (warnedAllKeys == NO) + { + warnedAllKeys = YES; + NSWarnLog(@"use of special 'allKeys' key works differently with only foundation base"); + } + + value = [self allKeys]; + } + else if ([key isEqualToString: @"count"]) + { + static BOOL warnedCount = NO; + if (warnedCount == NO) + { + warnedCount = YES; + NSWarnLog(@"use of special 'count' key works differently with only foundation base"); + } + + value = [NSNumber numberWithInt: [self count]]; + } + } + + //EOFLOGObjectLevelArgs(@"EOKVC", @"key=%@ value: %p (class %@)", + // key, value, [value class]); + EOFLOGObjectFnStopCond(@"EOKVC"); + + return value; +} + +- (id)storedValueForKey: (NSString *)key +{ + id value; + + EOFLOGObjectFnStartCond(@"EOKVC"); + //EOFLOGObjectLevelArgs(@"EOKVC", @"key=%@", + // key); + + value = [self objectForKey: key]; + + if (!value) + { + if ([key isEqualToString: @"allValues"]) + value = [self allValues]; + else if ([key isEqualToString: @"allKeys"]) + value = [self allKeys]; + else if ([key isEqualToString: @"count"]) + value = [NSNumber numberWithInt: [self count]]; + } + + //EOFLOGObjectLevelArgs(@"EOKVC", @"key=%@ value: %p (class=%@)", + // key, value, [value class]); + EOFLOGObjectFnStopCond(@"EOKVC"); + + return value; +} + +- (id)valueForKeyPath: (NSString*)keyPath +{ + id value = nil; + + EOFLOGObjectFnStartCond(@"EOKVC"); + //EOFLOGObjectLevelArgs(@"EOKVC", @"keyPath=\"%@\"", + // keyPath); + + if ([keyPath hasPrefix: @"'"]) //user defined composed key + { + NSMutableArray *keyPathArray = [[[[keyPath stringByDeletingPrefix: @"'"] + componentsSeparatedByString: @"."] + mutableCopy] autorelease]; + NSMutableString *key = [NSMutableString string]; + + //EOFLOGObjectLevelArgs(@"EOKVC", @"keyPathArray=%@", keyPathArray); + + while ([keyPathArray count] > 0) + { + id tmpKey; + + //EOFLOGObjectLevelArgs(@"EOKVC", @"keyPathArray=%@", keyPathArray); + + tmpKey = [keyPathArray objectAtIndex: 0]; + //EOFLOGObjectLevelArgs(@"EOKVC", @"tmpKey=%@", tmpKey); + + [keyPathArray removeObjectAtIndex: 0]; + + if ([key length] > 0) + [key appendString: @"."]; + if ([tmpKey hasSuffix: @"'"]) + { + tmpKey = [tmpKey stringByDeletingSuffix: @"'"]; + [key appendString: tmpKey]; + break; + } + else + [key appendString: tmpKey]; + + //EOFLOGObjectLevelArgs(@"EOKVC", @"key=%@", key); + } + + //EOFLOGObjectLevelArgs(@"EOKVC", @"key=%@", key); + + value = [self valueForKey: key]; + + //EOFLOGObjectLevelArgs(@"EOKVC",@"key=%@ tmpValue: %p (class=%@)", + // key,value,[value class]); + + if (value && [keyPathArray count] > 0) + { + NSString *rightKeyPath = [keyPathArray + componentsJoinedByString: @"."]; + + //EOFLOGObjectLevelArgs(@"EOKVC", @"rightKeyPath=%@", + // rightKeyPath); + + value = [value valueForKeyPath: rightKeyPath]; + } + } + else + { + //return super valueForKeyPath:keyPath only if there's no object for entire key keyPath + value = [self objectForKey: keyPath]; + + EOFLOGObjectLevelArgs(@"EOKVC",@"keyPath=%@ tmpValue: %p (class=%@)", + keyPath,value,[value class]); + + /* if([value isEqual:[EONull null]] == YES) //??? + value=nil; + else */ + + if (!value) + value = [super valueForKeyPath: keyPath]; + } + + //EOFLOGObjectLevelArgs(@"EOKVC",@"keyPath=%@ value: %p (class=%@)", + // keyPath,value,[value class]); + EOFLOGObjectFnStopCond(@"EOKVC"); + + return value; +} + +- (id)storedValueForKeyPath: (NSString*)keyPath +{ + id value = nil; + + EOFLOGObjectFnStartCond(@"EOKVC"); + //EOFLOGObjectLevelArgs(@"EOKVC",@"keyPath=\"%@\"", + // keyPath); + + if ([keyPath hasPrefix: @"'"]) //user defined composed key + { + NSMutableArray *keyPathArray = [[[[keyPath stringByDeletingPrefix: @"'"] + componentsSeparatedByString: @"."] + mutableCopy] autorelease]; + NSMutableString *key = [NSMutableString string]; + + //EOFLOGObjectLevelArgs(@"EOKVC", @"keyPathArray=%@", keyPathArray); + + while ([keyPathArray count] > 0) + { + id tmpKey; + + //EOFLOGObjectLevelArgs(@"EOKVC", @"keyPathArray=%@", keyPathArray); + + tmpKey = [keyPathArray objectAtIndex: 0]; + //EOFLOGObjectLevelArgs(@"EOKVC", @"tmpKey=%@", tmpKey); + + [keyPathArray removeObjectAtIndex: 0]; + + if ([key length] > 0) + [key appendString: @"."]; + if ([tmpKey hasSuffix: @"'"]) + { + tmpKey = [tmpKey stringByDeletingSuffix: @"'"]; + [key appendString: tmpKey]; + break; + } + else + [key appendString: tmpKey]; + + //EOFLOGObjectLevelArgs(@"EOKVC", @"key=%@", key); + } + + //EOFLOGObjectLevelArgs(@"EOKVC", @"key=%@", key); + + value = [self storedValueForKey: key]; + + //EOFLOGObjectLevelArgs(@"EOKVC",@"key=%@ tmpValue: %p (class=%@)", + // key,value,[value class]); + + if (value && [keyPathArray count] > 0) + { + NSString *rightKeyPath = [keyPathArray + componentsJoinedByString: @"."]; + + EOFLOGObjectLevelArgs(@"EOKVC", @"rightKeyPath=%@", + rightKeyPath); + + value = [value storedValueForKeyPath: rightKeyPath]; + } + } + else + { + //return super valueForKeyPath:keyPath only if there's no object for entire key keyPath + value = [self objectForKey: keyPath]; + + //EOFLOGObjectLevelArgs(@"EOKVC",@"keyPath=%@ tmpValue: %p (class=%@)", + // keyPath,value,[value class]); + + /* if([value isEqual:[EONull null]] == YES) //??? + value=nil; + else */ + + if (!value) + value = [super storedValueForKeyPath: keyPath]; + } + + //EOFLOGObjectLevelArgs(@"EOKVC",@"keyPath=%@ value: %p (class=%@)", + // keyPath,value,[value class]); + EOFLOGObjectFnStopCond(@"EOKVC"); + + return value; +} + +@end + + +@implementation NSMutableDictionary (EOKeyValueCoding) + +- (void)takeValue: (id)value + forKey: (NSString *)key +{ + EOFLOGObjectFnStartCond(@"EOKVC"); + + if (value) + [self setObject: value + forKey: key]; + else + [self removeObjectForKey: key]; + + EOFLOGObjectFnStopCond(@"EOKVC"); +} + +- (void)takeStoredValue: (id)value + forKey: (NSString *)key +{ + EOFLOGObjectFnStartCond(@"EOKVC"); + + if (value) + [self setObject: value + forKey: key]; + else + [self removeObjectForKey: key]; + + EOFLOGObjectFnStopCond(@"EOKVC"); +} + +- (void)smartTakeValue: (id)value + forKeyPath: (NSString*)keyPath +{ + [self takeValue:value + forKeyPath:keyPath + isSmart:YES]; +} + +- (void)takeValue: (id)value + forKeyPath: (NSString *)keyPath +{ + [self takeValue:value + forKeyPath:keyPath + isSmart:NO]; +} + +- (void)takeValue: (id)value + forKeyPath: (NSString *)keyPath + isSmart: (BOOL)smartFlag +{ + EOFLOGObjectFnStartCond(@"EOKVC"); + //EOFLOGObjectLevelArgs(@"EOKVC", @"keyPath=\"%@\"", + // keyPath); + + if ([keyPath hasPrefix: @"'"]) //user defined composed key + { + NSMutableArray *keyPathArray = [[[[keyPath stringByDeletingPrefix: @"'"] + componentsSeparatedByString: @"."] + mutableCopy] autorelease]; + NSMutableString *key = [NSMutableString string]; + + //EOFLOGObjectLevelArgs(@"EOKVC", @"keyPathArray=%@", keyPathArray); + + while ([keyPathArray count] > 0) + { + id tmpKey; + + //EOFLOGObjectLevelArgs(@"EOKVC", @"keyPathArray=%@", keyPathArray); + + tmpKey = [keyPathArray objectAtIndex: 0]; + //EOFLOGObjectLevelArgs(@"EOKVC", @"tmpKey=%@", tmpKey); + + [keyPathArray removeObjectAtIndex: 0]; + + if ([key length] > 0) + [key appendString: @"."]; + if ([tmpKey hasSuffix: @"'"]) + { + tmpKey = [tmpKey stringByDeletingSuffix: @"'"]; + [key appendString: tmpKey]; + break; + } + else + [key appendString: tmpKey]; + + //EOFLOGObjectLevelArgs(@"EOKVC", @"key=%@", key); + } + + //EOFLOGObjectLevelArgs(@"EOKVC",@"key=%@",key); + //EOFLOGObjectLevelArgs(@"EOKVC",@"left keyPathArray=\"%@\"", + // keyPathArray); + + if ([keyPathArray count] > 0) + { + id obj = [self objectForKey: key]; + + if (obj) + { + NSString *rightKeyPath = [keyPathArray + componentsJoinedByString: @"."]; + + //EOFLOGObjectLevelArgs(@"EOKVC",@"rightKeyPath=\"%@\"", + // rightKeyPath); + + if (smartFlag) + [obj smartTakeValue: value + forKeyPath: rightKeyPath]; + else + [obj takeValue: value + forKeyPath: rightKeyPath]; + } + } + else + { + if (value) + [self setObject: value + forKey: key]; + else + [self removeObjectForKey: key]; + } + } + else + { + if (value) + [self setObject: value + forKey: keyPath]; + else + [self removeObjectForKey: keyPath]; + } + + EOFLOGObjectFnStopCond(@"EOKVC"); +} + +- (void)takeStoredValue: (id)value + forKeyPath: (NSString *)keyPath +{ + EOFLOGObjectFnStartCond(@"EOKVC"); + //EOFLOGObjectLevelArgs(@"EOKVC",@"keyPath=\"%@\"", + // keyPath); + + if ([keyPath hasPrefix: @"'"]) //user defined composed key + { + NSMutableArray *keyPathArray = [[[[keyPath stringByDeletingPrefix: @"'"] + componentsSeparatedByString: @"."] + mutableCopy] autorelease]; + NSMutableString *key = [NSMutableString string]; + + //EOFLOGObjectLevelArgs(@"EOKVC", @"keyPathArray=%@", keyPathArray); + + while ([keyPathArray count] > 0) + { + id tmpKey; + + //EOFLOGObjectLevelArgs(@"EOKVC", @"keyPathArray=%@", keyPathArray); + + tmpKey = [keyPathArray objectAtIndex: 0]; + //EOFLOGObjectLevelArgs(@"EOKVC", @"tmpKey=%@", tmpKey); + + [keyPathArray removeObjectAtIndex: 0]; + + if ([key length] > 0) + [key appendString: @"."]; + + if ([tmpKey hasSuffix: @"'"]) + { + tmpKey = [tmpKey stringByDeletingSuffix: @"'"]; + [key appendString: tmpKey]; + break; + } + else + [key appendString: tmpKey]; + + //EOFLOGObjectLevelArgs(@"EOKVC", @"key=%@", key); + } + + //EOFLOGObjectLevelArgs(@"EOKVC", @"key=%@", key); + //EOFLOGObjectLevelArgs(@"EOKVC",@"left keyPathArray=\"%@\"", + // keyPathArray); + + if ([keyPathArray count] > 0) + { + id obj = [self objectForKey: key]; + + if (obj) + { + NSString *rightKeyPath = [keyPathArray + componentsJoinedByString: @"."]; + + //EOFLOGObjectLevelArgs(@"EOKVC",@"rightKeyPath=\"%@\"", + // rightKeyPath); + + [obj takeStoredValue: value + forKeyPath: rightKeyPath]; + } + } + else + { + if (value) + [self setObject: value + forKey: key]; + else + [self removeObjectForKey: key]; + } + } + else + { + if (value) + [self setObject: value + forKey: keyPath]; + else + [self removeObjectForKey: keyPath]; + } + + EOFLOGObjectFnStopCond(@"EOKVC"); +} + +@end diff --git a/EOControl/EOKeyValueCodingBase.h b/EOControl/EOKeyValueCodingBase.h new file mode 100644 index 0000000..ebfdb1a --- /dev/null +++ b/EOControl/EOKeyValueCodingBase.h @@ -0,0 +1,76 @@ +/* + EOKeyValueCodingBase.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOKeyValueCoding_h__ +#define __EOKeyValueCoding_h__ + +#if !FOUNDATION_HAS_KVC +#import +#import + +@class NSDictionary; + + + +@interface NSObject (EOKeyValueCodingPrimitives) + +- (id)valueForKey: (NSString *)key; +- (id)storedValueForKey: (NSString *)key; +- (void)takeValue: (id)value forKey: (NSString *)key; +- (void)takeStoredValue: (id)value forKey: (NSString *)key; ++ (BOOL)accessInstanceVariablesDirectly; ++ (BOOL)useStoredAccessor; + +@end + +@interface NSObject (EOKVCPAdditions) + +- (id)valueForKeyPath: (NSString *)key; +- (void)takeValue: value forKeyPath: (NSString *)key; +- (NSDictionary *)valuesForKeys: (NSArray *)keys; +- (void)takeValuesFromDictionary: (NSDictionary *)dictionary; + +@end + +@interface NSObject (EOKeyValueCodingException) + +- (id)handleQueryWithUnboundKey: (NSString *)key; +- (void)handleTakeValue: (id)value forUnboundKey: (NSString *)key; + +- (void)unableToSetNilForKey: (NSString *)key; + +@end + +@interface NSObject (EOKeyValueCodingCacheControl) + ++ (void)flushAllKeyBindings; + +@end + + +#endif + +#endif /* __EOKeyValueCodingBase_h__ */ diff --git a/EOControl/EOKeyValueCodingBase.m b/EOControl/EOKeyValueCodingBase.m new file mode 100644 index 0000000..6f9cb6f --- /dev/null +++ b/EOControl/EOKeyValueCodingBase.m @@ -0,0 +1,1989 @@ +/** + EOKeyValueCodingBase.m + + Copyright (C) 1996-2002 Free Software Foundation, Inc. + + Author: Mircea Oancea + Date: November 1996 + + Author: Mirko Viviani + Date: February 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#import +#import +#import + +#include "config.h" + +#if !FOUNDATION_HAS_KVC + +#import +#import + + +/* + * EOKeyValueCoding implementation + */ + +NSString *EOUnknownKeyException = @"EOUnknownKeyException"; +NSString *EOTargetObjectUserInfoKey = @"EOTargetObjectUserInfoKey"; +NSString *EOUnknownUserInfoKey = @"EOUnknownUserInfoKey"; + +@implementation NSObject (EOKVCPAdditions) + +/* + * Accessor functions + */ + +/* ACCESS to keys of id type. */ + +static id idMethodGetFunc(void *info1, void *info2, id self) +{ + id (*fptr)(id, SEL) = (id(*)(id, SEL))info1; + id val = fptr(self, (SEL)info2); + + return val; +} + +static id idIvarGetFunc(void *info1, void *info2, id self) +{ + id *ptr = (id*)((char*)self + (int)info2); + + return *ptr; +} + +static void idMethodSetFunc(void *info1, void *info2, id self, id val) +{ + void (*fptr)(id, SEL, id) = (void(*)(id, SEL, id))info1; + + fptr(self, (SEL)info2, val); +} + +static void idIvarSetFunc(void *info1, void *info2, id self, id val) +{ + id *ptr = (id*)((char*)self + (int)info2); + + [*ptr autorelease]; + *ptr = [val retain]; +} + +/* ACCESS to keys of char type. */ + +static id charMethodGetFunc(void *info1, void *info2, id self) +{ + char (*fptr)(id, SEL) = (char(*)(id, SEL))info1; + char val = fptr(self, (SEL)info2); + + return [NSNumber numberWithChar: val]; +} + +static id charIvarGetFunc(void *info1, void *info2, id self) +{ + char *ptr = (char*)((char*)self + (int)info2); + + return [NSNumber numberWithChar: *ptr]; +} + +static void charMethodSetFunc(void *info1, void *info2, id self, id val) +{ + void (*fptr)(id, SEL, char) = (void(*)(id, SEL, char))info1; + + fptr(self, (SEL)info2, [val charValue]); +} + +static void charIvarSetFunc(void *info1, void *info2, id self, id val) +{ + char *ptr = (char*)((char*)self + (int)info2); + + *ptr = [val charValue]; +} + + +/* ACCESS to keys of unsigned char type. */ + +static id unsignedCharMethodGetFunc(void *info1, void *info2, id self) +{ + unsigned char (*fptr)(id, SEL) = (unsigned char(*)(id, SEL))info1; + unsigned char val = fptr(self, (SEL)info2); + + return [NSNumber numberWithUnsignedChar: val]; +} + +static id unsignedCharIvarGetFunc(void *info1, void *info2, id self) +{ + unsigned char *ptr = (unsigned char*)((char*)self + (int)info2); + + return [NSNumber numberWithUnsignedChar: *ptr]; +} + +static void unsignedCharMethodSetFunc(void *info1, void *info2, id self, id val) +{ + void (*fptr)(id, SEL, unsigned char) = (void(*)(id, SEL, unsigned char))info1; + + fptr(self, (SEL)info2, [val unsignedCharValue]); +} + +static void unsignedCharIvarSetFunc(void *info1, void *info2, id self, id val) +{ + unsigned char *ptr = (unsigned char*)((char*)self + (int)info2); + + *ptr = [val unsignedCharValue]; +} + + +/* ACCESS to keys of short type. */ + +static id shortMethodGetFunc(void *info1, void *info2, id self) +{ + short (*fptr)(id, SEL) = (short(*)(id, SEL))info1; + short val = fptr(self, (SEL)info2); + + return [NSNumber numberWithShort: val]; +} + +static id shortIvarGetFunc(void *info1, void *info2, id self) +{ + short *ptr = (short*)((char*)self + (int)info2); + + return [NSNumber numberWithShort: *ptr]; +} + +static void shortMethodSetFunc(void *info1, void *info2, id self, id val) +{ + void (*fptr)(id, SEL, short) = (void(*)(id, SEL, short))info1; + + fptr(self, (SEL)info2, [val shortValue]); +} + +static void shortIvarSetFunc(void *info1, void *info2, id self, id val) +{ + short* ptr = (short*)((char*)self + (int)info2); + + *ptr = [val shortValue]; +} + + +/* ACCESS to keys of unsigned short type. */ + +static id unsignedShortMethodGetFunc(void *info1, void *info2, id self) +{ + unsigned short (*fptr)(id, SEL) = (unsigned short(*)(id, SEL))info1; + unsigned short val = fptr(self, (SEL)info2); + + return [NSNumber numberWithUnsignedShort: val]; +} + +static id unsignedShortIvarGetFunc(void *info1, void *info2, id self) +{ + unsigned short *ptr = (unsigned short*)((char*)self + (int)info2); + + return [NSNumber numberWithUnsignedShort: *ptr]; +} + +static void unsignedShortMethodSetFunc(void *info1, void *info2, id self, id val) +{ + void (*fptr)(id, SEL, unsigned short) = (void(*)(id, SEL, unsigned short))info1; + + fptr(self, (SEL)info2, [val unsignedShortValue]); +} + +static void unsignedShortIvarSetFunc(void *info1, void *info2, id self, id val) +{ + unsigned short *ptr = (unsigned short*)((char*)self + (int)info2); + + *ptr = [val unsignedShortValue]; +} + + +/* ACCESS to keys of int type. */ + +static id intMethodGetFunc(void *info1, void *info2, id self) +{ + int (*fptr)(id, SEL) = (int(*)(id, SEL))info1; + int val = fptr(self, (SEL)info2); + + return [NSNumber numberWithInt: val]; +} + +static id intIvarGetFunc(void *info1, void *info2, id self) +{ + int *ptr = (int*)((char*)self + (int)info2); + + return [NSNumber numberWithInt: *ptr]; +} + +static void intMethodSetFunc(void *info1, void *info2, id self, id val) +{ + void (*fptr)(id, SEL, int) = (void(*)(id, SEL, int))info1; + + fptr(self, (SEL)info2, [val intValue]); +} + +static void intIvarSetFunc(void *info1, void *info2, id self, id val) +{ + int *ptr = (int*)((char*)self + (int)info2); + + *ptr = [val intValue]; +} + + +/* ACCESS to keys of unsigned int type. */ + +static id unsignedIntMethodGetFunc(void *info1, void *info2, id self) +{ + unsigned int (*fptr)(id, SEL) = (unsigned int(*)(id, SEL))info1; + unsigned int val = fptr(self, (SEL)info2); + + return [NSNumber numberWithUnsignedInt: val]; +} + +static id unsignedIntIvarGetFunc(void *info1, void *info2, id self) +{ + unsigned int *ptr = (unsigned int*)((char*)self + (int)info2); + + return [NSNumber numberWithUnsignedInt: *ptr]; +} + +static void unsignedIntMethodSetFunc(void *info1, void *info2, id self, id val) +{ + void (*fptr)(id, SEL, unsigned int) = (void(*)(id, SEL, unsigned int))info1; + + fptr(self, (SEL)info2, [val unsignedIntValue]); +} + +static void unsignedIntIvarSetFunc(void *info1, void *info2, id self, id val) +{ + unsigned int* ptr = (unsigned int*)((char*)self + (int)info2); + + *ptr = [val unsignedIntValue]; +} + + +/* ACCESS to keys of long type. */ + +static id longMethodGetFunc(void *info1, void *info2, id self) +{ + long (*fptr)(id, SEL) = (long(*)(id, SEL))info1; + long val = fptr(self, (SEL)info2); + + return [NSNumber numberWithLong: val]; +} + +static id longIvarGetFunc(void *info1, void *info2, id self) +{ + long *ptr = (long*)((char*)self + (int)info2); + + return [NSNumber numberWithLong: *ptr]; +} + +static void longMethodSetFunc(void *info1, void *info2, id self, id val) +{ + void (*fptr)(id, SEL, long) = (void(*)(id, SEL, long))info1; + + fptr(self, (SEL)info2, [val longValue]); +} + +static void longIvarSetFunc(void *info1, void *info2, id self, id val) +{ + long *ptr = (long*)((char*)self + (int)info2); + + *ptr = [val longValue]; +} + + +/* ACCESS to keys of unsigned long type. */ + +static id unsignedLongMethodGetFunc(void *info1, void *info2, id self) +{ + unsigned long (*fptr)(id, SEL) = (unsigned long(*)(id, SEL))info1; + unsigned long val = fptr(self, (SEL)info2); + + return [NSNumber numberWithUnsignedLong: val]; +} + +static id unsignedLongIvarGetFunc(void *info1, void *info2, id self) +{ + unsigned long *ptr = (unsigned long*)((char*)self + (int)info2); + + return [NSNumber numberWithUnsignedLong: *ptr]; +} + +static void unsignedLongMethodSetFunc(void *info1, void *info2, id self, id val) +{ + void (*fptr)(id, SEL, unsigned long) = (void(*)(id, SEL, unsigned long))info1; + + fptr(self, (SEL)info2, [val unsignedLongValue]); +} + +static void unsignedLongIvarSetFunc(void *info1, void *info2, id self, id val) +{ + unsigned long *ptr = (unsigned long*)((char*)self + (int)info2); + + *ptr = [val unsignedLongValue]; +} + + +/* ACCESS to keys of long long type. */ + +static id longLongMethodGetFunc(void *info1, void *info2, id self) +{ + long long (*fptr)(id, SEL) = (long long(*)(id, SEL))info1; + long long val = fptr(self, (SEL)info2); + + return [NSNumber numberWithLongLong: val]; +} + +static id longLongIvarGetFunc(void *info1, void *info2, id self) +{ + long long *ptr = (long long*)((char*)self + (int)info2); + + return [NSNumber numberWithLongLong: *ptr]; +} + +static void longLongMethodSetFunc(void *info1, void *info2, id self, id val) +{ + void (*fptr)(id, SEL, long long) = (void(*)(id, SEL, long long))info1; + + fptr(self, (SEL)info2, [val longLongValue]); +} + +static void longLongIvarSetFunc(void *info1, void *info2, id self, id val) +{ + long long *ptr = (long long*)((char*)self + (int)info2); + + *ptr = [val longLongValue]; +} + + +/* ACCESS to keys of unsigned long long type. */ + +static id unsignedLongLongMethodGetFunc(void *info1, void *info2, id self) +{ + unsigned long long (*fptr)(id, SEL) = (unsigned long long(*)(id, SEL))info1; + unsigned long long val = fptr(self, (SEL)info2); + + return [NSNumber numberWithUnsignedLongLong: val]; +} + +static id unsignedLongLongIvarGetFunc(void *info1, void *info2, id self) +{ + unsigned long long *ptr = (unsigned long long*)((char*)self + (int)info2); + + return [NSNumber numberWithUnsignedLongLong: *ptr]; +} + +static void unsignedLongLongMethodSetFunc(void *info1, void *info2, id self, id val) +{ + void (*fptr)(id, SEL, unsigned long long) = (void(*)(id, SEL, unsigned long long))info1; + + fptr(self, (SEL)info2, [val unsignedLongLongValue]); +} + +static void unsignedLongLongIvarSetFunc(void *info1, void *info2, id self, id val) +{ + unsigned long long *ptr = (unsigned long long*)((char*)self + (int)info2); + + *ptr = [val unsignedLongLongValue]; +} + + +/* ACCESS to keys of float type. */ + +static id floatMethodGetFunc(void *info1, void *info2, id self) +{ + float (*fptr)(id, SEL) = (float(*)(id, SEL))info1; + float val = fptr(self, (SEL)info2); + + return [NSNumber numberWithFloat: val]; +} + +static id floatIvarGetFunc(void *info1, void *info2, id self) +{ + float *ptr = (float*)((char*)self + (int)info2); + + return [NSNumber numberWithFloat: *ptr]; +} + +static void floatMethodSetFunc(void *info1, void *info2, id self, id val) +{ + void (*fptr)(id, SEL, float) = (void(*)(id, SEL, float))info1; + + fptr(self, (SEL)info2, [val floatValue]); +} + +static void floatIvarSetFunc(void *info1, void *info2, id self, id val) +{ + float *ptr = (float*)((char*)self + (int)info2); + + *ptr = [val floatValue]; +} + + +/* ACCESS to keys of double type. */ + +static id doubleMethodGetFunc(void *info1, void *info2, id self) +{ + double (*fptr)(id, SEL) = (double(*)(id, SEL))info1; + double val = fptr(self, (SEL)info2); + + return [NSNumber numberWithDouble: val]; +} + +static id doubleIvarGetFunc(void *info1, void *info2, id self) +{ + double *ptr = (double*)((char*)self + (int)info2); + + return [NSNumber numberWithDouble: *ptr]; +} + +static void doubleMethodSetFunc(void *info1, void *info2, id self, id val) +{ + void (*fptr)(id, SEL, double) = (void(*)(id, SEL, double))info1; + + fptr(self, (SEL)info2, [val doubleValue]); +} + +static void doubleIvarSetFunc(void *info1, void *info2, id self, id val) +{ + double *ptr = (double*)((char*)self + (int)info2); + + *ptr = [val doubleValue]; +} + +/* + * Types + */ + +typedef struct _KeyValueMethod +{ + NSString *key; + Class class; +} KeyValueMethod; + +typedef struct _GetKeyValueBinding +{ + id (*access)(void*, void*, id); + void *info1; + void *info2; +} GetKeyValueBinding; + +typedef struct _SetKeyValueBinding +{ + void (*access)(void*, void*, id, id); + void *info1; + void *info2; +} SetKeyValueBinding; + +/* + * Globals + */ + +static NSMapTable *getValueBindings = NULL; +static NSMapTable *setValueBindings = NULL; +static NSMapTable *getStoredValueBindings = NULL; +static NSMapTable *setStoredValueBindings = NULL; +static BOOL keyValueDebug = NO; +static BOOL keyValueInit = NO; + +/* + * KeyValueMapping + */ + +static GetKeyValueBinding *newGetBinding(NSString *key, id instance) +{ + GetKeyValueBinding *ret = NULL; + void *info1 = NULL; + void *info2 = NULL; + BOOL accessInstanceVariables; + id (*fptr)(void*, void*, id) = NULL; + int count; + + Class class = [instance class]; + MetaClass mclass = class_get_meta_class(class); + const char *ckey = [key cString]; + char iname[strlen(ckey) + 4]; + SEL sel; + struct objc_method *mth; + + accessInstanceVariables = [NSObject accessInstanceVariablesDirectly]; + + // Lookup method name [- (type)key] + // Lookup method name [- (type)getKey] + count = 2; + + while (!fptr && count--) + { + if (count == 1) + { + Strcpy(iname, ckey); + } + else + { + Strcpy(iname, "get"); + Strcat(iname, ckey); + iname[3] = islower(iname[3]) ? toupper(iname[3]) : iname[3]; + } + + sel = sel_get_any_uid(iname); + + if (sel && ((mth = class_get_instance_method(class, sel)) + || (mth = class_get_class_method(mclass, sel))) + && method_get_number_of_arguments(mth) == 2) + { + switch (*objc_skip_type_qualifiers(mth->method_types)) + { + case _C_CLASS: + fptr = (id (*)(void*, void*, id))idMethodGetFunc; + break; + case _C_ID: + fptr = (id (*)(void*, void*, id))idMethodGetFunc; + break; + case _C_CHR: + fptr = (id (*)(void*, void*, id))charMethodGetFunc; + break; + case _C_UCHR: + fptr = (id (*)(void*, void*, id))unsignedCharMethodGetFunc; + break; + case _C_SHT: + fptr = (id (*)(void*, void*, id))shortMethodGetFunc; + break; + case _C_USHT: + fptr = (id (*)(void*, void*, id))unsignedShortMethodGetFunc; + break; + case _C_INT: + fptr = (id (*)(void*, void*, id))intMethodGetFunc; + break; + case _C_UINT: + fptr = (id (*)(void*, void*, id))unsignedIntMethodGetFunc; + break; + case _C_LNG: + fptr = (id (*)(void*, void*, id))longMethodGetFunc; + break; + case _C_ULNG: + fptr = (id (*)(void*, void*, id))unsignedLongMethodGetFunc; + break; + case 'q': + fptr = (id (*)(void*, void*, id))longLongMethodGetFunc; + break; + case 'Q': + fptr = (id (*)(void*, void*, id))unsignedLongLongMethodGetFunc; + break; + case _C_FLT: + fptr = (id (*)(void*, void*, id))floatMethodGetFunc; + break; + case _C_DBL: + fptr = (id (*)(void*, void*, id))doubleMethodGetFunc; + break; + } + + if (fptr) + { + info1 = (void*)(mth->method_imp); + info2 = (void*)(mth->method_name); + } + } + } + +// NSDebugFLog(@"accessInstanceVariables=%d",accessInstanceVariables); + // Lookup ivar name + + if (!fptr && accessInstanceVariables == YES) + { + int keyType=0; + + for (keyType = 0; !fptr && keyType < 2; keyType++) + { + const char *testKey = ckey; + char *testKeyDup = NULL; + + if (keyType==1) + { + int len=strlen(testKey); + + testKeyDup = malloc(len + 2); + + testKeyDup[0] = '_'; + strcpy(testKeyDup + 1,testKey); + + testKey = testKeyDup; + } + + class = [instance class]; + // NSDebugFLog(@"testKey=%s",testKey); + + while (!fptr && class) + { + int i; + + // NSDebugFLog(@"class=%@",NSStringFromClass(class)); + for (i = 0;!fptr && class->ivars && i < class->ivars->ivar_count; i++) + { + if (!Strcmp(testKey, class->ivars->ivar_list[i].ivar_name)) + { + // NSDebugFLog(@"Found"); + switch (*objc_skip_type_qualifiers(class->ivars->ivar_list[i].ivar_type)) + { + case _C_ID: + fptr = (id (*)(void*, void*, id))idIvarGetFunc; + break; + case _C_CHR: + fptr = (id (*)(void*, void*, id))charIvarGetFunc; + break; + case _C_UCHR: + fptr = (id (*)(void*, void*, id))unsignedCharIvarGetFunc; + break; + case _C_SHT: + fptr = (id (*)(void*, void*, id))shortIvarGetFunc; + break; + case _C_USHT: + fptr = (id (*)(void*, void*, id))unsignedShortIvarGetFunc; + break; + case _C_INT: + fptr = (id (*)(void*, void*, id))intIvarGetFunc; + break; + case _C_UINT: + fptr = (id (*)(void*, void*, id))unsignedIntIvarGetFunc; + break; + case _C_LNG: + fptr = (id (*)(void*, void*, id))longIvarGetFunc; + break; + case _C_ULNG: + fptr = (id (*)(void*, void*, id))unsignedLongIvarGetFunc; + break; + case 'q': + fptr = (id (*)(void*, void*, id))longLongIvarGetFunc; + break; + case 'Q': + fptr = (id (*)(void*, void*, id))unsignedLongLongIvarGetFunc; + break; + case _C_FLT: + fptr = (id (*)(void*, void*, id))floatIvarGetFunc; + break; + case _C_DBL: + fptr = (id (*)(void*, void*, id))doubleIvarGetFunc; + break; + } + + if (fptr) + { + info2 = (void*)(class->ivars->ivar_list[i].ivar_offset); + } + } + } + + class = class->super_class; + } + + if (testKeyDup) + { + free(testKeyDup); + testKeyDup=NULL; + } + } + } + +// NSDebugFLog(@"fptr=%p",fptr); + + // Make binding and insert into map + + if (fptr) + { + KeyValueMethod* mkey = Malloc(sizeof(KeyValueMethod)); + GetKeyValueBinding* bin = Malloc(sizeof(GetKeyValueBinding)); + + mkey->key = [key copy]; + mkey->class = [instance class]; + + bin->access = fptr; + bin->info1 = info1; + bin->info2 = info2; + + NSMapInsert(getValueBindings, mkey, bin); + ret = bin; + } + + // If no way to access value warn + if (!ret && keyValueDebug) + NSLog(@"cannnot get key `%@' for instance of class `%@'", + key, NSStringFromClass([instance class])); + + return ret; +} + +static GetKeyValueBinding *newGetStoredBinding(NSString *key, id instance) +{ + GetKeyValueBinding *ret = NULL; + void *info1 = NULL; + void *info2 = NULL; + BOOL accessInstanceVariables; + id (*fptr)(void*, void*, id) = NULL; + int count; + + Class class = [instance class]; + MetaClass mclass = class_get_meta_class(class); + const char *ckey = [key cString]; + char iname[strlen(ckey) + 5]; + SEL sel; + struct objc_method *mth; + + accessInstanceVariables = [NSObject accessInstanceVariablesDirectly]; + + // Lookup method name [- (type)_key] + // Lookup method name [- (type)_getKey] + count = 2; + + while (!fptr && count--) + { + if(count == 1) + { + Strcpy(iname, "_"); + Strcat(iname, ckey); + } + else + { + Strcpy(iname, "_get"); + Strcat(iname, ckey); + iname[4] = islower(iname[4]) ? toupper(iname[4]) : iname[4]; + } + + sel = sel_get_any_uid(iname); + + if (sel && ((mth = class_get_instance_method(class, sel)) + || (mth = class_get_class_method(mclass, sel))) + && method_get_number_of_arguments(mth) == 2) + { + switch (*objc_skip_type_qualifiers(mth->method_types)) + { + case _C_CLASS: + fptr = (id (*)(void*, void*, id))idMethodGetFunc; + break; + case _C_ID: + fptr = (id (*)(void*, void*, id))idMethodGetFunc; + break; + case _C_CHR: + fptr = (id (*)(void*, void*, id))charMethodGetFunc; + break; + case _C_UCHR: + fptr = (id (*)(void*, void*, id))unsignedCharMethodGetFunc; + break; + case _C_SHT: + fptr = (id (*)(void*, void*, id))shortMethodGetFunc; + break; + case _C_USHT: + fptr = (id (*)(void*, void*, id))unsignedShortMethodGetFunc; + break; + case _C_INT: + fptr = (id (*)(void*, void*, id))intMethodGetFunc; + break; + case _C_UINT: + fptr = (id (*)(void*, void*, id))unsignedIntMethodGetFunc; + break; + case _C_LNG: + fptr = (id (*)(void*, void*, id))longMethodGetFunc; + break; + case _C_ULNG: + fptr = (id (*)(void*, void*, id))unsignedLongMethodGetFunc; + break; + case 'q': + fptr = (id (*)(void*, void*, id))longLongMethodGetFunc; + break; + case 'Q': + fptr = (id (*)(void*, void*, id))unsignedLongLongMethodGetFunc; + break; + case _C_FLT: + fptr = (id (*)(void*, void*, id))floatMethodGetFunc; + break; + case _C_DBL: + fptr = (id (*)(void*, void*, id))doubleMethodGetFunc; + break; + } + + if (fptr) + { + info1 = (void*)(mth->method_imp); + info2 = (void*)(mth->method_name); + } + } + } + + // Lookup ivar name + count = 2; + + while (!fptr && count-- && accessInstanceVariables == YES) + { + int i; + + // Make ivar from name + if(count == 1) + { + Strcpy(iname, "_"); + Strcat(iname, ckey); + } + else + { + Strcpy(iname, ckey); + } + + while (class) + { + for (i = 0; class->ivars && i < class->ivars->ivar_count; i++) + { + if (!Strcmp(iname, class->ivars->ivar_list[i].ivar_name)) + { + switch (*objc_skip_type_qualifiers(class->ivars->ivar_list[i].ivar_type)) + { + case _C_ID: + fptr = (id (*)(void*, void*, id))idIvarGetFunc; + break; + case _C_CHR: + fptr = (id (*)(void*, void*, id))charIvarGetFunc; + break; + case _C_UCHR: + fptr = (id (*)(void*, void*, id))unsignedCharIvarGetFunc; + break; + case _C_SHT: + fptr = (id (*)(void*, void*, id))shortIvarGetFunc; + break; + case _C_USHT: + fptr = (id (*)(void*, void*, id))unsignedShortIvarGetFunc; + break; + case _C_INT: + fptr = (id (*)(void*, void*, id))intIvarGetFunc; + break; + case _C_UINT: + fptr = (id (*)(void*, void*, id))unsignedIntIvarGetFunc; + break; + case _C_LNG: + fptr = (id (*)(void*, void*, id))longIvarGetFunc; + break; + case _C_ULNG: + fptr = (id (*)(void*, void*, id))unsignedLongIvarGetFunc; + break; + case 'q': + fptr = (id (*)(void*, void*, id))longLongIvarGetFunc; + break; + case 'Q': + fptr = (id (*)(void*, void*, id))unsignedLongLongIvarGetFunc; + break; + case _C_FLT: + fptr = (id (*)(void*, void*, id))floatIvarGetFunc; + break; + case _C_DBL: + fptr = (id (*)(void*, void*, id))doubleIvarGetFunc; + break; + } + + if (fptr) + { + info2 = (void*)(class->ivars->ivar_list[i].ivar_offset); + break; + } + } + } + + class = class->super_class; + } + } + + // Lookup method name [- (type)key] + // Lookup method name [- (type)getKey] + count = 2; + class = [instance class]; + + while (!fptr && count--) + { + if (count == 1) + { + Strcpy(iname, ckey); + } + else + { + Strcpy(iname, "get"); + Strcat(iname, ckey); + iname[3] = islower(iname[3]) ? toupper(iname[3]) : iname[3]; + } + + sel = sel_get_any_uid(iname); + + if (sel && ((mth = class_get_instance_method(class, sel)) + || (mth = class_get_class_method(mclass, sel))) + && method_get_number_of_arguments(mth) == 2) + { + switch (*objc_skip_type_qualifiers(mth->method_types)) + { + case _C_ID: + fptr = (id (*)(void*, void*, id))idMethodGetFunc; + break; + case _C_CHR: + fptr = (id (*)(void*, void*, id))charMethodGetFunc; + break; + case _C_UCHR: + fptr = (id (*)(void*, void*, id))unsignedCharMethodGetFunc; + break; + case _C_SHT: + fptr = (id (*)(void*, void*, id))shortMethodGetFunc; + break; + case _C_USHT: + fptr = (id (*)(void*, void*, id))unsignedShortMethodGetFunc; + break; + case _C_INT: + fptr = (id (*)(void*, void*, id))intMethodGetFunc; + break; + case _C_UINT: + fptr = (id (*)(void*, void*, id))unsignedIntMethodGetFunc; + break; + case _C_LNG: + fptr = (id (*)(void*, void*, id))longMethodGetFunc; + break; + case _C_ULNG: + fptr = (id (*)(void*, void*, id))unsignedLongMethodGetFunc; + break; + case 'q': + fptr = (id (*)(void*, void*, id))longLongMethodGetFunc; + break; + case 'Q': + fptr = (id (*)(void*, void*, id))unsignedLongLongMethodGetFunc; + break; + case _C_FLT: + fptr = (id (*)(void*, void*, id))floatMethodGetFunc; + break; + case _C_DBL: + fptr = (id (*)(void*, void*, id))doubleMethodGetFunc; + break; + } + + if (fptr) + { + info1 = (void*)(mth->method_imp); + info2 = (void*)(mth->method_name); + } + } + } + + // Make binding and insert into map + if (fptr) + { + KeyValueMethod* mkey = Malloc(sizeof(KeyValueMethod)); + GetKeyValueBinding* bin = Malloc(sizeof(GetKeyValueBinding)); + + mkey->key = [key copy]; + mkey->class = [instance class]; + + bin->access = fptr; + bin->info1 = info1; + bin->info2 = info2; + + NSMapInsert(getStoredValueBindings, mkey, bin); + ret = bin; + } + + // If no way to access value warn + if (!ret && keyValueDebug) + NSLog(@"cannnot get key `%@' for instance of class `%@'", + key, NSStringFromClass([instance class])); + + return ret; +} + +static SetKeyValueBinding *newSetBinding(NSString *key, id instance, id value) +{ + SetKeyValueBinding *ret = NULL; + void *info1 = NULL; + void *info2 = NULL; + void (*fptr)(void*, void*, id, id) = NULL; + BOOL idMethod = NO; + + // Lookup method name [-(void)setKey:(type)arg] + { + Class class = [instance class]; + const char *ckey = [key cString]; + SEL sel; + struct objc_method *mth; + char sname[Strlen(ckey)+7]; + + // Make sel from name + Strcpy(sname, "set"); + Strcat(sname, ckey); + Strcat(sname, ":"); + sname[3] = islower(sname[3]) ? toupper(sname[3]) : sname[3]; + + sel = sel_get_any_uid(sname); + + if (sel && (mth = class_get_instance_method(class, sel)) + && method_get_number_of_arguments(mth) == 3 + && *objc_skip_type_qualifiers(mth->method_types) == _C_VOID) + { + char* argType = (char*)(mth->method_types); + + argType = (char*)objc_skip_argspec(argType); // skip return + argType = (char*)objc_skip_argspec(argType); // skip self + argType = (char*)objc_skip_argspec(argType); // skip SEL + + switch (*objc_skip_type_qualifiers(argType)) + { + case _C_ID: + fptr = (void (*)(void*, void*, id, id))idMethodSetFunc; + idMethod = YES; + break; + case _C_CHR: + fptr = (void (*)(void*, void*, id, id))charMethodSetFunc; + break; + case _C_UCHR: + fptr = (void (*)(void*, void*, id, id))unsignedCharMethodSetFunc; + break; + case _C_SHT: + fptr = (void (*)(void*, void*, id, id))shortMethodSetFunc; + break; + case _C_USHT: + fptr = (void (*)(void*, void*, id, id))unsignedShortMethodSetFunc; + break; + case _C_INT: + fptr = (void (*)(void*, void*, id, id))intMethodSetFunc; + break; + case _C_UINT: + fptr = (void (*)(void*, void*, id, id))unsignedIntMethodSetFunc; + break; + case _C_LNG: + fptr = (void (*)(void*, void*, id, id))longMethodSetFunc; + break; + case _C_ULNG: + fptr = (void (*)(void*, void*, id, id))unsignedLongMethodSetFunc; + break; + case 'q': + fptr = (void (*)(void*, void*, id, id))longLongMethodSetFunc; + break; + case 'Q': + fptr = (void (*)(void*, void*, id, id))unsignedLongLongMethodSetFunc; + break; + case _C_FLT: + fptr = (void (*)(void*, void*, id, id))floatMethodSetFunc; + break; + case _C_DBL: + fptr = (void (*)(void*, void*, id, id))doubleMethodSetFunc; + break; + } + + if (fptr) + { + info1 = (void*)(mth->method_imp); + info2 = (void*)(mth->method_name); + } + } + } + + // Lookup ivar name +// NSDebugFLog(@"accessInstanceVariablesDirectly=%d",[NSObject accessInstanceVariablesDirectly]); + + if (!fptr && [NSObject accessInstanceVariablesDirectly]) + { + const char *ckey = [key cString]; + int keyType=0; + + for (keyType = 0; !fptr && keyType < 2; keyType++) + { + const char* testKey=ckey; + char* testKeyDup=NULL; + Class class = [instance class]; + + if (keyType==1) + { + int len=strlen(testKey); + testKeyDup=malloc(len+2); + testKeyDup[0]='_'; + strcpy(testKeyDup+1,testKey); + testKey=testKeyDup; + } + + // NSDebugFLog(@"testKey=%s",testKey); + + while (!fptr && class) + { + int i; + + // NSDebugFLog(@"class=%@",NSStringFromClass(class)); + + for (i = 0; + !fptr && class->ivars && i < class->ivars->ivar_count; + i++) + { + if (!Strcmp(testKey, class->ivars->ivar_list[i].ivar_name)) + { + // NSDebugFLog(@"Found"); + + switch (*objc_skip_type_qualifiers(class->ivars->ivar_list[i].ivar_type)) + { + case _C_ID: + fptr = (void (*)(void*, void*, id, id))idIvarSetFunc; + idMethod = YES; + break; + case _C_CHR: + fptr = (void (*)(void*, void*, id, id))charIvarSetFunc; + break; + case _C_UCHR: + fptr = (void (*)(void*, void*, id, id))unsignedCharIvarSetFunc; + break; + case _C_SHT: + fptr = (void (*)(void*, void*, id, id))shortIvarSetFunc; + break; + case _C_USHT: + fptr = (void (*)(void*, void*, id, id))unsignedShortIvarSetFunc; + break; + case _C_INT: + fptr = (void (*)(void*, void*, id, id))intIvarSetFunc; + break; + case _C_UINT: + fptr = (void (*)(void*, void*, id, id))unsignedIntIvarSetFunc; + break; + case _C_LNG: + fptr = (void (*)(void*, void*, id, id))longIvarSetFunc; + break; + case _C_ULNG: + fptr = (void (*)(void*, void*, id, id))unsignedLongIvarSetFunc; + break; + case 'q': + fptr = (void (*)(void*, void*, id, id))longLongIvarSetFunc; + break; + case 'Q': + fptr = (void (*)(void*, void*, id, id))unsignedLongLongIvarSetFunc; + break; + case _C_FLT: + fptr = (void (*)(void*, void*, id, id))floatIvarSetFunc; + break; + case _C_DBL: + fptr = (void (*)(void*, void*, id, id))doubleIvarSetFunc; + break; + } + if (fptr) { + info2 = (void*)(class->ivars->ivar_list[i].ivar_offset); + } + } + } + class = class->super_class; + } + + if (testKeyDup) + { + free(testKeyDup); + testKeyDup = NULL; + } + } + } + +// NSDebugFLog(@"fptr=%p",fptr); + + if (fptr && !idMethod && value == nil) + return (SetKeyValueBinding *) - 1; + + // Make binding and insert into map + + if (fptr) + { + KeyValueMethod *mkey = Malloc(sizeof(KeyValueMethod)); + SetKeyValueBinding *bin = Malloc(sizeof(SetKeyValueBinding)); + + mkey->key = [key copy]; + mkey->class = [instance class]; + + bin->access = fptr; + bin->info1 = info1; + bin->info2 = info2; + + NSMapInsert(setValueBindings, mkey, bin); + ret = bin; + } + // If no way to access value warn + if (!ret && keyValueDebug) + NSLog(@"cannnot set key `%@' for instance of class `%@'", + key, NSStringFromClass([instance class])); + + return ret; +} + +static SetKeyValueBinding *newSetStoredBinding(NSString *key, id instance, id value) +{ + SetKeyValueBinding *ret = NULL; + void *info1 = NULL; + void *info2 = NULL; + void (*fptr)(void*, void*, id, id) = NULL; + BOOL idMethod = NO; + + // Lookup ivar _name + { + Class class = [instance class]; + const char* ckey = [key cString]; + char iname[Strlen(ckey) + 2]; + int i; + + // Make ivar from name + Strcpy(iname, "_"); + Strcat(iname, ckey); + + while (class) + { + for (i = 0; class->ivars && i < class->ivars->ivar_count; i++) + { + if (!Strcmp(iname, class->ivars->ivar_list[i].ivar_name)) + { + switch (*objc_skip_type_qualifiers(class->ivars->ivar_list[i].ivar_type)) + { + case _C_ID: + fptr = (void (*)(void*, void*, id, id))idIvarSetFunc; + idMethod = YES; + break; + case _C_CHR: + fptr = (void (*)(void*, void*, id, id))charIvarSetFunc; + break; + case _C_UCHR: + fptr = (void (*)(void*, void*, id, id))unsignedCharIvarSetFunc; + break; + case _C_SHT: + fptr = (void (*)(void*, void*, id, id))shortIvarSetFunc; + break; + case _C_USHT: + fptr = (void (*)(void*, void*, id, id))unsignedShortIvarSetFunc; + break; + case _C_INT: + fptr = (void (*)(void*, void*, id, id))intIvarSetFunc; + break; + case _C_UINT: + fptr = (void (*)(void*, void*, id, id))unsignedIntIvarSetFunc; + break; + case _C_LNG: + fptr = (void (*)(void*, void*, id, id))longIvarSetFunc; + break; + case _C_ULNG: + fptr = (void (*)(void*, void*, id, id))unsignedLongIvarSetFunc; + break; + case 'q': + fptr = (void (*)(void*, void*, id, id))longLongIvarSetFunc; + break; + case 'Q': + fptr = (void (*)(void*, void*, id, id))unsignedLongLongIvarSetFunc; + break; + case _C_FLT: + fptr = (void (*)(void*, void*, id, id))floatIvarSetFunc; + break; + case _C_DBL: + fptr = (void (*)(void*, void*, id, id))doubleIvarSetFunc; + break; + } + + if (fptr) + { + info2 = (void*)(class->ivars->ivar_list[i].ivar_offset); + break; + } + } + } + + class = class->super_class; + } + } + + // Lookup method name [-(void)_setKey:(type)arg] + if (!fptr) + { + Class class = [instance class]; + const char* ckey = [key cString]; + SEL sel; + struct objc_method* mth; + char sname[Strlen(ckey) + 7]; + + // Make sel from name + Strcpy(sname, "_set"); + Strcat(sname, ckey); + Strcat(sname, ":"); + sname[3] = islower(sname[3]) ? toupper(sname[3]) : sname[3]; + sel = sel_get_any_uid(sname); + + if (sel && (mth = class_get_instance_method(class, sel)) + && method_get_number_of_arguments(mth) == 3 + && *objc_skip_type_qualifiers(mth->method_types) == _C_VOID) + { + char *argType = (char*)(mth->method_types); + + argType = (char*)objc_skip_argspec(argType); // skip return + argType = (char*)objc_skip_argspec(argType); // skip self + argType = (char*)objc_skip_argspec(argType); // skip SEL + + switch (*objc_skip_type_qualifiers(argType)) + { + case _C_ID: + fptr = (void (*)(void*, void*, id, id))idMethodSetFunc; + idMethod = YES; + break; + case _C_CHR: + fptr = (void (*)(void*, void*, id, id))charMethodSetFunc; + break; + case _C_UCHR: + fptr = (void (*)(void*, void*, id, id))unsignedCharMethodSetFunc; + break; + case _C_SHT: + fptr = (void (*)(void*, void*, id, id))shortMethodSetFunc; + break; + case _C_USHT: + fptr = (void (*)(void*, void*, id, id))unsignedShortMethodSetFunc; + break; + case _C_INT: + fptr = (void (*)(void*, void*, id, id))intMethodSetFunc; + break; + case _C_UINT: + fptr = (void (*)(void*, void*, id, id))unsignedIntMethodSetFunc; + break; + case _C_LNG: + fptr = (void (*)(void*, void*, id, id))longMethodSetFunc; + break; + case _C_ULNG: + fptr = (void (*)(void*, void*, id, id))unsignedLongMethodSetFunc; + break; + case 'q': + fptr = (void (*)(void*, void*, id, id))longLongMethodSetFunc; + break; + case 'Q': + fptr = (void (*)(void*, void*, id, id))unsignedLongLongMethodSetFunc; + break; + case _C_FLT: + fptr = (void (*)(void*, void*, id, id))floatMethodSetFunc; + break; + case _C_DBL: + fptr = (void (*)(void*, void*, id, id))doubleMethodSetFunc; + break; + } + + if (fptr) + { + info1 = (void*)(mth->method_imp); + info2 = (void*)(mth->method_name); + } + } + } + + // Lookup ivar name + if (!fptr) + { + Class class = [instance class]; + const char* ckey = [key cString]; + int i; + + while (class) + { + for (i = 0; class->ivars && i < class->ivars->ivar_count; i++) + { + if (!Strcmp(ckey, class->ivars->ivar_list[i].ivar_name)) + { + switch (*objc_skip_type_qualifiers(class->ivars->ivar_list[i].ivar_type)) + { + case _C_ID: + fptr = (void (*)(void*, void*, id, id))idIvarSetFunc; + idMethod = YES; + break; + case _C_CHR: + fptr = (void (*)(void*, void*, id, id))charIvarSetFunc; + break; + case _C_UCHR: + fptr = (void (*)(void*, void*, id, id))unsignedCharIvarSetFunc; + break; + case _C_SHT: + fptr = (void (*)(void*, void*, id, id))shortIvarSetFunc; + break; + case _C_USHT: + fptr = (void (*)(void*, void*, id, id))unsignedShortIvarSetFunc; + break; + case _C_INT: + fptr = (void (*)(void*, void*, id, id))intIvarSetFunc; + break; + case _C_UINT: + fptr = (void (*)(void*, void*, id, id))unsignedIntIvarSetFunc; + break; + case _C_LNG: + fptr = (void (*)(void*, void*, id, id))longIvarSetFunc; + break; + case _C_ULNG: + fptr = (void (*)(void*, void*, id, id))unsignedLongIvarSetFunc; + break; + case 'q': + fptr = (void (*)(void*, void*, id, id))longLongIvarSetFunc; + break; + case 'Q': + fptr = (void (*)(void*, void*, id, id))unsignedLongLongIvarSetFunc; + break; + case _C_FLT: + fptr = (void (*)(void*, void*, id, id))floatIvarSetFunc; + break; + case _C_DBL: + fptr = (void (*)(void*, void*, id, id))doubleIvarSetFunc; + break; + } + + if (fptr) + { + info2 = (void*)(class->ivars->ivar_list[i].ivar_offset); + break; + } + } + } + + class = class->super_class; + } + } + + // Lookup method name [-(void)setKey:(type)arg] + if (!fptr) + { + Class class = [instance class]; + const char* ckey = [key cString]; + SEL sel; + struct objc_method* mth; + char sname[Strlen(ckey) + 7]; + + // Make sel from name + Strcpy(sname, "set"); + Strcat(sname, ckey); + Strcat(sname, ":"); + sname[3] = islower(sname[3]) ? toupper(sname[3]) : sname[3]; + sel = sel_get_any_uid(sname); + + if (sel && (mth = class_get_instance_method(class, sel)) + && method_get_number_of_arguments(mth) == 3 + && *objc_skip_type_qualifiers(mth->method_types) == _C_VOID) + { + char *argType = (char*)(mth->method_types); + + argType = (char*)objc_skip_argspec(argType); // skip return + argType = (char*)objc_skip_argspec(argType); // skip self + argType = (char*)objc_skip_argspec(argType); // skip SEL + + switch (*objc_skip_type_qualifiers(argType)) + { + case _C_ID: + fptr = (void (*)(void*, void*, id, id))idMethodSetFunc; + idMethod = YES; + break; + case _C_CHR: + fptr = (void (*)(void*, void*, id, id))charMethodSetFunc; + break; + case _C_UCHR: + fptr = (void (*)(void*, void*, id, id))unsignedCharMethodSetFunc; + break; + case _C_SHT: + fptr = (void (*)(void*, void*, id, id))shortMethodSetFunc; + break; + case _C_USHT: + fptr = (void (*)(void*, void*, id, id))unsignedShortMethodSetFunc; + break; + case _C_INT: + fptr = (void (*)(void*, void*, id, id))intMethodSetFunc; + break; + case _C_UINT: + fptr = (void (*)(void*, void*, id, id))unsignedIntMethodSetFunc; + break; + case _C_LNG: + fptr = (void (*)(void*, void*, id, id))longMethodSetFunc; + break; + case _C_ULNG: + fptr = (void (*)(void*, void*, id, id))unsignedLongMethodSetFunc; + break; + case 'q': + fptr = (void (*)(void*, void*, id, id))longLongMethodSetFunc; + break; + case 'Q': + fptr = (void (*)(void*, void*, id, id))unsignedLongLongMethodSetFunc; + break; + case _C_FLT: + fptr = (void (*)(void*, void*, id, id))floatMethodSetFunc; + break; + case _C_DBL: + fptr = (void (*)(void*, void*, id, id))doubleMethodSetFunc; + break; + } + + if (fptr) + { + info1 = (void*)(mth->method_imp); + info2 = (void*)(mth->method_name); + } + } + } + + if (fptr && !idMethod && value == nil) + return (SetKeyValueBinding *)-1; + + // Make binding and insert into map + if (fptr) + { + KeyValueMethod* mkey = Malloc(sizeof(KeyValueMethod)); + SetKeyValueBinding* bin = Malloc(sizeof(SetKeyValueBinding)); + + mkey->key = [key copy]; + mkey->class = [instance class]; + + bin->access = fptr; + bin->info1 = info1; + bin->info2 = info2; + + NSMapInsert(setStoredValueBindings, mkey, bin); + ret = bin; + } + + // If no way to access value warn + if (!ret && keyValueDebug) + NSLog(@"cannnot set key `%@' for instance of class `%@'", + key, NSStringFromClass([instance class])); + + return ret; +} + +/* + * MapTable initialization + */ + +static unsigned keyValueMapHash(NSMapTable *table, KeyValueMethod *map) +{ + return [map->key hash] + (((int)(map->class)) >> 4); +} + +static BOOL keyValueMapCompare(NSMapTable *table, + KeyValueMethod *map1, KeyValueMethod *map2) +{ + return (map1->class == map2->class) && [map1->key isEqual: map2->key]; +} + +static void mapRetainNothing(NSMapTable *table, KeyValueMethod *map) +{ +} + +static void keyValueMapKeyRelease(NSMapTable *table, KeyValueMethod *map) +{ + [map->key release]; + Free(map); +} + +static void keyValueMapValRelease(NSMapTable *table, void *map) +{ + Free(map); +} + +static NSString *keyValueMapDescribe(NSMapTable *table, KeyValueMethod *map) +{ + return [NSString stringWithFormat: @"%@:%@", + NSStringFromClass(map->class), map->key]; +} + +static NSString *describeBinding(NSMapTable *table, GetKeyValueBinding *bin) +{ + return [NSString stringWithFormat: @"%08x:%08x", bin->info1, bin->info2]; +} + +static NSMapTableKeyCallBacks keyValueKeyCallbacks = + { + (unsigned(*)(NSMapTable *, const void *))keyValueMapHash, + (BOOL(*)(NSMapTable *, const void *, const void *))keyValueMapCompare, + (void (*)(NSMapTable *, const void *anObject))mapRetainNothing, + (void (*)(NSMapTable *, void *anObject))keyValueMapKeyRelease, + (NSString *(*)(NSMapTable *, const void *))keyValueMapDescribe, + (const void *)NULL + }; + +const NSMapTableValueCallBacks keyValueValueCallbacks = + { + (void (*)(NSMapTable *, const void *))mapRetainNothing, + (void (*)(NSMapTable *, void *))keyValueMapValRelease, + (NSString *(*)(NSMapTable *, const void *))describeBinding + }; + +static void initKeyValueBindings(void) +{ + getValueBindings = NSCreateMapTable(keyValueKeyCallbacks, + keyValueValueCallbacks, 31); + setValueBindings = NSCreateMapTable(keyValueKeyCallbacks, + keyValueValueCallbacks, 31); + getStoredValueBindings = NSCreateMapTable(keyValueKeyCallbacks, + keyValueValueCallbacks, 31); + setStoredValueBindings = NSCreateMapTable(keyValueKeyCallbacks, + keyValueValueCallbacks, 31); + keyValueInit = YES; +} + +/* + * Access Methods + */ + +static inline void removeAllBindings(void) +{ + NSResetMapTable(getValueBindings); + NSResetMapTable(setValueBindings); + NSResetMapTable(getStoredValueBindings); + NSResetMapTable(setStoredValueBindings); +} + +static inline id getValue(NSString *key, id instance, BOOL *found) +{ + KeyValueMethod mkey = {key, [instance class]}; + GetKeyValueBinding *bin; + id value = nil; + + // Check Init + if (!keyValueInit) + initKeyValueBindings(); + + // NSDebugFLog(@"after init"); + // Get existing binding + bin = (GetKeyValueBinding *)NSMapGet(getValueBindings, &mkey); + + // Create new binding + if (!bin) + bin = newGetBinding(key, instance); + + // Get value if binding is ok + if (bin) + { +// NSDebugFLog(@"bin->"); + value = bin->access(bin->info1, bin->info2, instance); +// NSDebugFLog(@"after bin->"); + *found = YES; + } + + return value; +} + +static inline id getStoredValue(NSString *key, id instance, BOOL *found) +{ + KeyValueMethod mkey = {key, [instance class]}; + GetKeyValueBinding *bin; + id value = nil; + + // Check Init + if (!keyValueInit) + initKeyValueBindings(); + + // Get existing binding + bin = (GetKeyValueBinding *)NSMapGet(getStoredValueBindings, &mkey); + + // Create new binding + if (!bin) + bin = newGetStoredBinding(key, instance); + + // Get value if binding is ok + if (bin) + { + value = bin->access(bin->info1, bin->info2, instance); + *found = YES; + } + + return value; +} + +static inline BOOL setValue(NSString *key, id instance, id value) +{ + KeyValueMethod mkey = {key, [instance class]}; + SetKeyValueBinding *bin; + + // Check Init + if(!keyValueInit) + initKeyValueBindings(); + + // Get existing binding + bin = (SetKeyValueBinding *)NSMapGet(setValueBindings, &mkey); + + // Create new binding + if (!bin) + bin = newSetBinding(key, instance, value); + + if (bin == (SetKeyValueBinding *)-1) + { + [instance unableToSetNilForKey:key]; + return YES; + } + + // Get value if binding is ok + if (bin) + bin->access(bin->info1, bin->info2, instance, value); + + return (bin != NULL); +} + +static inline BOOL setStoredValue(NSString *key, id instance, id value) +{ + KeyValueMethod mkey = {key, [instance class]}; + SetKeyValueBinding *bin; + + // Check Init + if (!keyValueInit) + initKeyValueBindings(); + + // Get existing binding + bin = (SetKeyValueBinding *)NSMapGet(setStoredValueBindings, &mkey); + + // Create new binding + if (!bin) + bin = newSetStoredBinding(key, instance, value); + + if (bin == (SetKeyValueBinding *) - 1) + { + [instance unableToSetNilForKey: key]; + return YES; + } + + // Get value if binding is ok + if(bin) + bin->access(bin->info1, bin->info2, instance, value); + + return (bin != NULL); +} + +/* + * Methods + */ + +- (void)setKeyValueCodingWarnings: (BOOL)aFlag //REMOVE +{ + keyValueDebug = aFlag; +} + +- (id)valueForKeyPath: (NSString *)key +{ + NSArray *pathArray = [key componentsSeparatedByString: @"."]; + NSEnumerator *pathEnum; + NSString *path; + id obj = self; + + pathEnum = [pathArray objectEnumerator]; + while ((path = [pathEnum nextObject])) + { + obj = [obj valueForKey: path]; + } + + return obj; +} + +- (void)takeValue: value forKeyPath: (NSString *)key +{ + NSArray *pathArray = [key componentsSeparatedByString: @"."]; + NSString *path; + id obj = self; + int i, count; + + count = [pathArray count]; + + for (i = 0; i < (count - 1); i++) + { + path = [pathArray objectAtIndex: i]; + obj = [obj valueForKey: path]; + } + + path = [pathArray lastObject]; + [obj takeValue: value forKey: path]; +} + +- (NSDictionary *)valuesForKeys: (NSArray *)keys +{ + int i, n = [keys count]; + NSMutableArray *newKeys = [[[NSMutableArray alloc] initWithCapacity: n] + autorelease]; + NSMutableArray *newVals = [[[NSMutableArray alloc] initWithCapacity: n] + autorelease]; + EONull *null = [EONull null]; + + for (i = 0; i < n; i++) + { + id key = [keys objectAtIndex: i]; + id val = [self valueForKey: key]; + + if (val == nil) + val = null; + + [newKeys addObject: key]; + [newVals addObject: val]; + } + + return [NSDictionary dictionaryWithObjects: newVals forKeys: newKeys]; +} + +- (void)takeValuesFromDictionary: (NSDictionary *)dictionary +{ + NSEnumerator *keyEnum = [dictionary keyEnumerator]; + id key; + id val; + + while ((key = [keyEnum nextObject])) + { + val = [dictionary objectForKey: key]; + + if ([val isKindOfClass: [[EONull null] class]]) + val = nil; + + [self takeValue: val forKey: key]; + } +} + +@end + + // Implemented in NSObject +@implementation NSObject (EOKeyValueCodingPrimitives) + +- (id)valueForKey: (NSString *)key +{ + BOOL found = NO; + id val = nil; + +// NSDebugFLog(@"valueForKey:"); + + val = getValue(key, self, &found); + + if (found == NO) + val = [self handleQueryWithUnboundKey: key]; + + return val; +} + +- (void)takeValue: (id)value + forKey: (NSString *)key +{ + if (!setValue(key, self, value)) + [self handleTakeValue: value forUnboundKey: key]; +} + +- (id)storedValueForKey: (NSString *)key +{ + BOOL found = NO; + id val = getStoredValue(key, self, &found); + + if (found == NO) + val = [self handleQueryWithUnboundKey: key]; + + return val; +} + +- (void)takeStoredValue: (id)value forKey: (NSString *)key +{ + if (!setStoredValue(key, self, value)) + [self handleTakeValue: value forUnboundKey: key]; +} + ++ (BOOL)accessInstanceVariablesDirectly +{ + return YES; +} + ++ (BOOL)useStoredAccessor +{ + return NO; +} + +@end + + +@implementation NSObject (EOKeyValueCodingCacheControl) + ++ (void)flushAllKeyBindings +{ + removeAllBindings(); +} + ++ (void)flushClassKeyBindings +{ + removeAllBindings(); +} + +@end + + +/* + * EOKeyValueCodingException raises an exception by default + */ + +@implementation NSObject (EOKeyValueCodingException) + +- (id)handleQueryWithUnboundKey: (NSString *)key +{ + NSString *reason=nil; + + reason = [NSString stringWithFormat: @"%@ -- %@ 0x%x: cannot find value for key \"%@\"", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + key]; + + [[NSException exceptionWithName: EOUnknownKeyException + reason: reason + userInfo: [NSDictionary dictionaryWithObjectsAndKeys: + self, EOTargetObjectUserInfoKey, + key, EOUnknownUserInfoKey, + nil]] raise]; + return nil; +} + +- (void)handleTakeValue: (id)value + forUnboundKey: (NSString *)key +{ + NSString *reason=nil; + + reason = [NSString stringWithFormat: @"%@ -- %@ 0x%x: cannot set value \"%@\" for key \"%@\"", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + value, + key]; + + [[NSException exceptionWithName: EOUnknownKeyException + reason: reason + userInfo: [NSDictionary dictionaryWithObjectsAndKeys: + self, EOTargetObjectUserInfoKey, + key, EOUnknownUserInfoKey, + nil]] raise]; +} + +- (void)unableToSetNilForKey: (NSString *)key +{ + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: cannot set EONull value for key \"%@\"", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), + self, + key]; +} + +@end + + +#endif diff --git a/EOControl/EOKeyValueQualifier.m b/EOControl/EOKeyValueQualifier.m new file mode 100644 index 0000000..fa43c6c --- /dev/null +++ b/EOControl/EOKeyValueQualifier.m @@ -0,0 +1,258 @@ +/** + EOKeyValueQualifier.m EOKeyValueQualifier Class + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + Author: Manuel Guesdon + Date: November 2001 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import + +#import +#import +#import +#import +#import +#import + +#import +#import +#import +#import +#import + + +@implementation EOKeyValueQualifier + ++ (EOKeyValueQualifier *)qualifierWithKey: (NSString *)key + operatorSelector: (SEL)selector + value: (id)value +{ + return [[[self alloc] initWithKey: key + operatorSelector: selector + value: value] autorelease]; +} + +- initWithKey: (NSString *)key +operatorSelector: (SEL)selector + value: (id)value +{ + //OK + if ((self = [super init])) + { + _selector = selector; + ASSIGN(_key, key); + ASSIGN(_value, value); + } + + return self; +} + +- (void)dealloc +{ + DESTROY(_key); + DESTROY(_value); + + [super dealloc]; +} + +- (SEL)selector +{ + return _selector; +} + +- (NSString *)key +{ + return _key; +} + +- (id)value +{ + return _value; +} + +- (id)copyWithZone: (NSZone *)zone +{ + EOKeyValueQualifier *qual = [[EOKeyValueQualifier allocWithZone: zone] init]; + + qual->_selector = _selector; + ASSIGN(qual->_key, _key); //Don't copy it [_key copyWithZone:zone]; + ASSIGN(qual->_value, _value); //Don't copy it: if this is a generic record, it isn't copyable [_value copyWithZone:zone]; + + return qual; +} + +- (BOOL)evaluateWithObject: (id)object +{ + id key; + + key = [object valueForKey: _key]; + + if (sel_eq(_selector, EOQualifierOperatorEqual) == YES) + { + return [key compare: _value] == NSOrderedSame; + } + else if (sel_eq(_selector, EOQualifierOperatorNotEqual) == YES) + { + return [key compare: _value] != NSOrderedSame; + } + else if (sel_eq(_selector, EOQualifierOperatorLessThan) == YES) + { + return [key compare: _value] == NSOrderedAscending; + } + else if (sel_eq(_selector, EOQualifierOperatorGreaterThan) == YES) + { + return [key compare: _value] == NSOrderedDescending; + } + else if (sel_eq(_selector, EOQualifierOperatorLessThanOrEqualTo) == YES) + { + return [key compare: _value] != NSOrderedDescending; + } + else if (sel_eq(_selector, EOQualifierOperatorGreaterThanOrEqualTo) == YES) + { + return [key compare: _value] != NSOrderedAscending; + } + else if (sel_eq(_selector, EOQualifierOperatorContains) == YES) + { + [self notImplemented: _cmd]; + } + else if (sel_eq(_selector, EOQualifierOperatorLike) == YES) + { + NSEmitTODO(); //TODO + return [key isEqual: _value] == NSOrderedSame; + } + else if (sel_eq(_selector, EOQualifierOperatorCaseInsensitiveLike) == YES) + { + NSEmitTODO(); //TODO + return [[key uppercaseString] isEqual: [_value uppercaseString]] + == NSOrderedSame; + } + + return NO; +} + +- (NSString *)description +{ +/* //TODO revoir + NSString *dscr=nil; + int i=0; + dscr = [NSString stringWithFormat:@"<%s %p - %@ %@ (%@)%@>", + object_get_class_name(self), + (void*)self, + _key, + NSStringFromSelector(_selector), + NSStringFromClass([_value class]), + _value]; + return dscr; +*/ + + return [NSString stringWithFormat:@"<%s %p - %@ %@ (%@)'%@'>", + object_get_class_name(self), + (void*)self, + _key, + [isa stringForOperatorSelector:_selector], + NSStringFromClass([_value class]), + _value]; +} + + +- (id) validateKeysWithRootClassDescription: (id)param0 +{ + return [self notImplemented: _cmd]; //TODO +} + +- (id) initWithKeyValueUnarchiver: (id)param0 +{ + return [self notImplemented: _cmd]; //TODO +} + +- (void) encodeWithKeyValueArchiver: (id)param0 +{ + [self notImplemented: _cmd]; //TODO +} + +- (void) _addBindingsToDictionary: (id)param0 +{ + [self notImplemented: _cmd]; //TODO +} + +- (EOQualifier *) qualifierWithBindings: (NSDictionary*)bindings + requiresAllVariables: (BOOL)requiresAllVariables +{ + EOFLOGObjectLevelArgs(@"EOQualifier", @"bindings=%@", bindings); + + if ([bindings count] > 0) + { + NSEmitTODO(); + return [self notImplemented: _cmd]; //TODO + } + else + return self; +} + +- (EOQualifier *) qualifierMigratedFromEntity: (id)param0 + relationshipPath: (id)param1 +{ + return [self notImplemented: _cmd]; //TODO +} + +@end + +@implementation EOKeyValueQualifier (EOKeyValueArchiving) + +- (id) initWithKeyValueUnarchiver: (EOKeyValueUnarchiver*)unarchiver +{ + EOFLOGObjectFnStartOrCond(@"EOQualifier"); + + if ((self = [self init])) + { + NSString *selectorName = [unarchiver decodeObjectForKey: @"selectorName"]; + + if (selectorName) + _selector = NSSelectorFromString(selectorName); + + ASSIGN(_key, [unarchiver decodeObjectForKey: @"key"]); + ASSIGN(_value, [unarchiver decodeObjectForKey: @"value"]); + } + + EOFLOGObjectFnStopOrCond(@"EOQualifier"); + + return self; +} + +- (void) encodeWithKeyValueArchiver: (EOKeyValueUnarchiver*)archiver +{ + [self notImplemented: _cmd]; +} + +@end diff --git a/EOControl/EOMutableKnownKeyDictionary.h b/EOControl/EOMutableKnownKeyDictionary.h new file mode 100644 index 0000000..1a93941 --- /dev/null +++ b/EOControl/EOMutableKnownKeyDictionary.h @@ -0,0 +1,168 @@ +/* + EOMultipleKnownKeyDictionary.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: October 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOMultipleKnownKeyDictionary_h__ +#define __EOMultipleKnownKeyDictionary_h__ + +#import +#import +#import +#import + +@class EOMutableKnownKeyDictionary; + +@interface EOMKKDInitializer : GCObject +{ + unsigned int _count; + NSMapTable *_keyToIndex; //key to index + NSString **_keys; +} + ++ (EOMKKDInitializer*)initializerFromKeyArray:(NSArray*)keys; ++ (id)newWithKeyArray: (NSArray*)keys; ++ (id)newWithKeyArray: (NSArray*)keys + zone: (NSZone*)zone; + +- (id)initWithKeys: (NSArray*)keys; +- (void) dealloc; +- (NSString*)description; +- (unsigned int) count; +- (void) setObject: (id)object + forIndex: (unsigned int)index + dictionary: (NSMutableDictionary*)dictionary; +- (id) objectForIndex: (unsigned int)index + dictionary: (NSDictionary*)dictionary; +- (unsigned int) indexForKey: (id)key; +- (id) arrayMappingForKeys: (id)keys; +- (id) subsetMappingForSourceDictionaryInitializer: (EOMKKDInitializer*)initialize + sourceKeys: (NSArray*)sourceKeys + destinationKeys: (NSArray*)destinationKeys; +- (id) subsetMappingForSourceDictionaryInitializer: (id)param0; +- (id*) keys; +- (BOOL)hasKey: (id)key; + +@end + +@interface EOMKKDKeyEnumerator : NSEnumerator +{ + EOMutableKnownKeyDictionary *_target; + int _position; + int _end; + // id* tvalues; + id _extraEnumerator; + NSString **_keys; +} + +- (id) initWithTarget: (EOMutableKnownKeyDictionary*)target; +- (void) dealloc; +- (NSString*)description; +- (id) nextObject; + +@end + +@interface EOMKKDSubsetMapping : NSObject +{ +@public + EOMKKDInitializer *_sourceDescription; + EOMKKDInitializer *_destinationDescription; + int _sourceOffsetForDestinationOffset[1]; +} + ++(id)newInstanceWithKeyCount: (unsigned int)keyCount + sourceDescription: (EOMKKDInitializer*)source + destinationDescription: (EOMKKDInitializer*)destination + zone: (NSZone*)zone; +- (void) dealloc; +- (NSString*)description; + +@end + +@interface EOMKKDArrayMapping : NSObject +{ +@public + EOMKKDInitializer *_destinationDescription; + int _destinationOffsetForArrayIndex[1]; +} ++ (id)newInstanceWithKeyCount: (unsigned int)keyCount + destinationDescription: (EOMKKDInitializer*)destination + zone: (NSZone*)zone; +- (void) dealloc; +- (NSString*)description; + +@end + + +@interface EOMutableKnownKeyDictionary : NSMutableDictionary +{ + EOMKKDInitializer *_MKKDInitializer; + NSMutableDictionary *_extraData; + id *_values; +} + ++ (id)dictionaryFromDictionary: (NSDictionary *)dict + subsetMapping: (EOMKKDSubsetMapping *)subsetMapping; ++ (id)newDictionaryFromDictionary: (NSDictionary*)dict + subsetMapping: (EOMKKDSubsetMapping*)subsetMapping + zone: (NSZone*)zone; ++ (id)newDictionaryWithObjects: (id*)objects + arrayMapping: (id)mapping + zone: (NSZone*)zone; ++ (id)newWithInitializer: (EOMKKDInitializer*)initializer + objects: (id*)objects + zone: (NSZone*)zone; ++ (id)dictionaryWithObjects: (NSArray*)objects + forKeys: (NSArray*)keys; + ++ (EOMKKDInitializer*)initializerFromKeyArray: (NSArray*)keys; ++ (id) dictionaryWithInitializer: (EOMKKDInitializer*)initializer; ++ (id)newWithInitializer: (EOMKKDInitializer*)initializer; ++ (id)newWithInitializer: (EOMKKDInitializer*)initializer + zone: (NSZone*)zone; ++ (id) dictionaryWithInitializer: (EOMKKDInitializer*)initializer; + +- (id)initWithInitializer: (EOMKKDInitializer*)initializer; +- (id) initWithInitializer: (EOMKKDInitializer*)initializer + objects: (id*)objects; +- (id) initWithObjects: (id*)objects + forKeys: (id*)keys + count: (unsigned int)count; +- (void) dealloc; +- (unsigned int) count; +- (id) objectForKey: (id)key; +- (void) setObject: (id)object + forKey: (NSString*)key; +- (void) removeObjectForKey: (NSString*)key; +- (BOOL) containsObjectsNotIdenticalTo: (id)object; +- (void) addEntriesFromDictionary: (NSDictionary*)dictionary; +- (NSEnumerator*) keyEnumerator; +- (EOMKKDInitializer*) eoMKKDInitializer; +- (NSMutableDictionary*)extraData; +- (BOOL)hasKey:(id)key; +- (NSString *)debugDescription; + +@end + +#endif diff --git a/EOControl/EOMutableKnownKeyDictionary.m b/EOControl/EOMutableKnownKeyDictionary.m new file mode 100644 index 0000000..be29f7e --- /dev/null +++ b/EOControl/EOMutableKnownKeyDictionary.m @@ -0,0 +1,947 @@ +/** + EEOMutableKnownKeyDictionary.m EEOMutableKnownKeyDictionary + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: October 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import + +#import +#import +#import + + +@implementation EOMKKDInitializer + ++ (EOMKKDInitializer*)initializerFromKeyArray: (NSArray*)keys +{ + EOMKKDInitializer *initializer = [[self newWithKeyArray: keys] autorelease]; + + return initializer; +} + ++ (id)newWithKeyArray: (NSArray*)keys +{ + return [[self alloc] + initWithKeys: keys]; +} + ++ (id)newWithKeyArray: (NSArray*)keys + zone: (NSZone*)zone +{ + return [[self allocWithZone: zone] + initWithKeys: keys]; +} + +- (id)initWithKeys: (id*)keys + count: (int)count +{ + if ((self = [self init])) + { + int i; + + NSAssert(keys, @"No array of keys"); + NSAssert(count > 0, @"No keys in array"); + + _keyToIndex = NSCreateMapTableWithZone(NSObjectMapKeyCallBacks, + NSIntMapValueCallBacks, + count, + [self zone]); + _keys = NSZoneMalloc([self zone], count * sizeof(NSString*)); + + EOFLOGObjectLevelArgs(@"EOMKKD", @"keys=%p _keys=%p", keys, _keys); + + for (i = 0; i < count; i++) + { + id key = keys[i]; + void *oldValue; + + _count = i + 1; + + EOFLOGObjectLevelArgs(@"EOMKKD", @"key=%p", key); + EOFLOGObjectLevelArgs(@"EOMKKD", @"key=%@ RETAINCOUNT=%d", + key, [key retainCount]); + + oldValue = NSMapInsertIfAbsent(_keyToIndex,key, (const void*)(i + 1)); //+1 because 0 = no object + _keys[i] = key; //Don't retain: already retained by Map + + EOFLOGObjectLevelArgs(@"EOMKKD", @"key=%@ RETAINCOUNT=%d", + key, [key retainCount]); + NSAssert1(!oldValue, @"%@ already present", key); + } + + EOFLOGObjectLevelArgs(@"EOMKKD", @"self=%p", self); + } + + return self; +} + +- (id)initWithKeys: (NSArray*)keys +{ + int count = [keys count]; + + NSAssert(keys, @"No array of keys"); + NSAssert([keys count] > 0, @"No keys in array"); + + { + id keysArray[count]; + + memset(keysArray, 0, count * sizeof(id)); + [keys getObjects: keysArray]; + + if ((self = [self initWithKeys: keysArray + count: count])) + { + } + } + + EOFLOGObjectLevelArgs(@"EOMKKD", @"self=%p", self); + + return self; +} + +- (void)dealloc +{ + EOFLOGObjectLevelArgs(@"EOMKKD", @"Deallocate EOMKKDInitliazer %p", self); + + if (_keyToIndex) + NSFreeMapTable(_keyToIndex); + if (_keys) + NSZoneFree([self zone],_keys); + + [super dealloc]; + + //EOFLogC("GSWElementIDString end of dealloc"); +} + +- (void)gcDecrementRefCountOfContainedObjects +{ +// [X gcDecrementRefCount]; +} + +- (BOOL)gcIncrementRefCountOfContainedObjects +{ + if (![super gcIncrementRefCountOfContainedObjects]) + return NO; + + //[XX gcIncrementRefCount]; + //[XX gcIncrementRefCountOfContainedObjects]; + return YES; +} + +- (NSString*)description +{ + NSString *dscr; + int i; + + dscr = [NSString stringWithFormat: @"<%s %p - keys=", + object_get_class_name(self), + (void*)self]; + + for (i = 0; i < _count; i++) + { + dscr = [dscr stringByAppendingFormat: @"%@ [%d] ", + _keys[i], + i]; + } + + dscr = [dscr stringByAppendingString: @">"]; + + return dscr; +} + +- (void) setObject: (id)object + forIndex: (unsigned int)index + dictionary: (NSMutableDictionary*)dictionary +{ + //OK? + id key; + + NSAssert2(index < _count, @"bad index %d (count=%u)", index, _count); + + key = _keys[index]; + + [dictionary setObject: object + forKey: key]; +} + +- (id) objectForIndex: (unsigned int)index + dictionary: (NSDictionary*)dictionary +{ + id key; + + NSAssert2(index < _count, @"bad index %d (count=%u)", index, _count); + + key = _keys[index]; + + return [dictionary objectForKey: key]; +} + +- (unsigned int) indexForKey: (NSString*)key +{ + void *index = NSMapGet(_keyToIndex, (const void *)key); + + if (!index) + return NSNotFound; + else + return (unsigned int)(index - 1); +} + +- (BOOL)hasKey: (id)key +{ + return ([self indexForKey: key] != NSNotFound); +} + +- (EOMKKDArrayMapping*) arrayMappingForKeys: (NSArray*)keys +{ + int selfKeyCount = [keys count]; + int keyCount = [keys count]; + EOMKKDArrayMapping *arrayMapping; + int i; + + NSAssert(keyCount <= selfKeyCount, @"key count greater than our key count"); + + arrayMapping = [[EOMKKDArrayMapping newInstanceWithKeyCount: selfKeyCount + destinationDescription: self + zone: [self zone]] autorelease]; + + for (i = 0; i < keyCount; i++) + { + NSString *key = [keys objectAtIndex: i]; + int destinationIndex = [self indexForKey:key]; + + arrayMapping->_destinationOffsetForArrayIndex[i] = destinationIndex + 1; + } + + return arrayMapping; +} + +- (EOMKKDSubsetMapping*) subsetMappingForSourceDictionaryInitializer: (EOMKKDInitializer*)sourceInitializer + sourceKeys: (NSArray*)sourceKeys + destinationKeys: (NSArray*)destinationKeys +{ + unsigned int selfKeyCount = [self count]; + unsigned int keyCount = [destinationKeys count]; + EOMKKDSubsetMapping *subsetMapping; + int i; + + NSAssert([sourceKeys count] == keyCount, @"Source and destination keys count are different"); + NSAssert(keyCount <= selfKeyCount, @"key count greater than our key count"); + + subsetMapping = [[EOMKKDSubsetMapping newInstanceWithKeyCount: selfKeyCount + sourceDescription: sourceInitializer + destinationDescription: self + zone: [self zone]] autorelease]; + + EOFLOGObjectLevelArgs(@"EOMKKD", @"sourceDescription=%@", sourceInitializer); + EOFLOGObjectLevelArgs(@"EOMKKD", @"destinationDescription=%@", self); + EOFLOGObjectLevelArgs(@"EOMKKD", @"sourceKeys=%@", sourceKeys); + EOFLOGObjectLevelArgs(@"EOMKKD", @"destinationKeys=%@", destinationKeys); + + for (i = 0; i < keyCount; i++) + { + NSString *sourceKey; + NSString *destinationKey; + int destinationIndex; + int sourceIndex; + + sourceKey = [sourceKeys objectAtIndex: i]; + EOFLOGObjectLevelArgs(@"EOMKKD", @"sourceKey=%@", sourceKey); + + destinationKey = [destinationKeys objectAtIndex: i]; + EOFLOGObjectLevelArgs(@"EOMKKD", @"destinationKey=%@", destinationKey); + + destinationIndex = [self indexForKey: destinationKey]; + EOFLOGObjectLevelArgs(@"EOMKKD", @"destinationIndex=%d", + destinationIndex); + + sourceIndex = [sourceInitializer indexForKey: sourceKey]; + EOFLOGObjectLevelArgs(@"EOMKKD", @"sourceIndex=%d", sourceIndex); + + NSAssert2(destinationIndex != NSNotFound, + @"Key %@ not found in %@", + destinationKey, + self); + NSAssert2(sourceIndex != NSNotFound, + @"Key %@ not found in %@", + sourceKey, + sourceInitializer); + + subsetMapping->_sourceOffsetForDestinationOffset[destinationIndex] + = sourceIndex + 1; + } + + return subsetMapping; +} + +- (EOMKKDSubsetMapping*)subsetMappingForSourceDictionaryInitializer: (EOMKKDInitializer*)sourceInitializer +{ + unsigned keyCount = [self count]; + EOMKKDSubsetMapping *subsetMapping = [[EOMKKDSubsetMapping + newInstanceWithKeyCount: keyCount + sourceDescription: sourceInitializer + destinationDescription: self + zone: [self zone]] autorelease]; + int i; + + for (i = 0; i < keyCount; i++) + { + NSString *key; + int index; + + key = _keys[i]; + EOFLOGObjectLevelArgs(@"EOMKKD", @"key=%@", key); + + index = [sourceInitializer indexForKey: key]; + EOFLOGObjectLevelArgs(@"EOMKKD", @"index=%d", index); + + subsetMapping->_sourceOffsetForDestinationOffset[i] + = (index == NSNotFound ? 0 : index + 1); + } + + return subsetMapping; +} + +- (id*) keys +{ + return _keys; +} + +- (unsigned int) count +{ + return _count; +} + +@end + + +@implementation EOMKKDKeyEnumerator : NSEnumerator + +- (id) initWithTarget: (EOMutableKnownKeyDictionary*)target +{ + if ((self = [super init])) + { + EOMKKDInitializer *initializer; + + NSAssert(target,@"No target"); + + ASSIGN(_target,target); + ASSIGN(_extraEnumerator, [[_target extraData] keyEnumerator]); + + initializer = [_target eoMKKDInitializer]; + _end = [initializer count]; + _keys = [initializer keys]; + } + + return self; +} + +- (void) dealloc +{ +// EOFLOGObjectLevelArgs(@"EOMKKD",@"Deallocate EOMKKDEnumerator %p (target=%p)",self,_target); + DESTROY(_target); + DESTROY(_extraEnumerator); + + [super dealloc]; +} + +- (NSString*)description +{ + NSString *dscr; + + dscr = [NSString stringWithFormat: @"<%s %p - target=%p>", + object_get_class_name(self), + (void*)self, + _target]; + return dscr; +} + +- (id) nextObject +{ + id object = nil; + + if (_position < _end) + { + object = _keys[_position]; + _position++; + } + else if (_extraEnumerator) + { + object = [_extraEnumerator nextObject]; + + if (object) + _position++; + } + + return object; +} + +@end + +@implementation EOMKKDSubsetMapping + ++ (id)newInstanceWithKeyCount: (unsigned int)keyCount + sourceDescription: (EOMKKDInitializer*)source + destinationDescription: (EOMKKDInitializer*)destination + zone: (NSZone*)zone +{ + unsigned extraBytes = (keyCount > 0 ? (keyCount - 1) : 0) * sizeof(int); + EOMKKDSubsetMapping *subsetMapping; + + subsetMapping = (EOMKKDSubsetMapping*)NSAllocateObject([EOMKKDSubsetMapping class], + extraBytes, + zone); + [subsetMapping init]; + + ASSIGN(subsetMapping-> _sourceDescription,source); + ASSIGN(subsetMapping-> _destinationDescription,destination); + + memset(subsetMapping-> _sourceOffsetForDestinationOffset, 0, + extraBytes + sizeof(int)); + + return subsetMapping; +} + +- (void) dealloc +{ + DESTROY(_sourceDescription); + DESTROY(_destinationDescription); + + [super dealloc]; +} + +- (NSString*)description +{ + NSString *dscr; + NSMutableString *offsets = [NSMutableString string]; + int i; + int count = [_destinationDescription count]; + + dscr = [NSString stringWithFormat: @"<%s %p - ", + object_get_class_name(self), + (void*)self]; + dscr = [dscr stringByAppendingFormat: @"\nsourceDescription=%@", + [_sourceDescription description]]; + dscr = [dscr stringByAppendingFormat: @"\ndestinationDescription=%@", + [_destinationDescription description]]; + + for (i = 0; i < count; i++) + [offsets appendFormat: @" %d", _sourceOffsetForDestinationOffset[i]]; + + dscr = [dscr stringByAppendingFormat: + @"\nsourceOffsetForDestinationOffset:%@>", offsets]; + + return dscr; +} + +@end + +@implementation EOMKKDArrayMapping + ++ (id)dictionaryFromDictionary: (NSDictionary *)dict + subsetMapping: (EOMKKDSubsetMapping *)subsetMapping +{ + return [[self newDictionaryFromDictionary: dict + subsetMapping: subsetMapping + zone: NULL] autorelease]; +} + ++ (id)newInstanceWithKeyCount: (unsigned int)keyCount + destinationDescription: (EOMKKDInitializer*)destination + zone: (NSZone*)zone +{ + unsigned extraBytes = (keyCount > 0 ? (keyCount - 1) : 0) * sizeof(int); + EOMKKDArrayMapping *arrayMapping; + + arrayMapping = (EOMKKDArrayMapping*)NSAllocateObject([EOMKKDArrayMapping class], + extraBytes, + zone); + [arrayMapping init]; + + ASSIGN(arrayMapping->_destinationDescription, destination); + memset(arrayMapping->_destinationOffsetForArrayIndex, 0, + extraBytes + sizeof(int)); + + return arrayMapping; +} + +- (void) dealloc +{ + DESTROY(_destinationDescription); + + [super dealloc]; +} + +- (NSString*)description +{ + NSString *dscr; + + dscr = [NSString stringWithFormat: @"<%s %p >", + object_get_class_name(self), + (void*)self]; + return dscr; +} + +@end + + +@implementation EOMutableKnownKeyDictionary + ++ (id)dictionaryFromDictionary: (NSDictionary *)dict + subsetMapping: (EOMKKDSubsetMapping *)subsetMapping +{ + return [[self newDictionaryFromDictionary: dict + subsetMapping: subsetMapping + zone: NULL] autorelease]; +} + ++ (id)newDictionaryFromDictionary: (NSDictionary*)dict + subsetMapping: (EOMKKDSubsetMapping*)subsetMapping + zone: (NSZone*)zone +{ + EOMutableKnownKeyDictionary *newDict = nil; + int objectsCount; + + NSAssert(dict, @"No dictionary"); + NSAssert(subsetMapping, @"No subsetMapping"); + + EOFLOGObjectLevelArgs(@"EOMKKD", @"dict=%@", dict); + EOFLOGObjectLevelArgs(@"EOMKKD", @"subsetMapping->_sourceDescription=%@", + subsetMapping->_sourceDescription); + EOFLOGObjectLevelArgs(@"EOMKKD", @"subsetMapping->_destinationDescription=%@", + subsetMapping->_destinationDescription); + + objectsCount = [subsetMapping->_destinationDescription count]; + EOFLOGObjectLevelArgs(@"EOMKKD", @"objectsCount=%d", objectsCount); + + if (objectsCount > 0) + { + id objects[objectsCount]; + int i; + + for (i = 0; i < objectsCount; i++) + { + objects[i] = nil; + + if (subsetMapping->_sourceOffsetForDestinationOffset[i] > 0) + { + int index = subsetMapping->_sourceOffsetForDestinationOffset[i] - 1; + + EOFLOGObjectLevelArgs(@"EOMKKD", @"index=%d", index); + + objects[i] = [subsetMapping->_sourceDescription + objectForIndex: index + dictionary: dict]; + + EOFLOGObjectLevelArgs(@"EOMKKD", @"objects[i]=%@", objects[i]); + NSAssert2(objects[i], @"No object for index %d from row %@", + index, + dict); + } + } + + newDict = [self newWithInitializer: subsetMapping->_destinationDescription + objects: objects + zone: zone]; + } + else + newDict = [self newWithInitializer: subsetMapping->_destinationDescription + zone: zone]; + + EOFLOGObjectLevelArgs(@"EOMKKD", @"END"); + + return newDict; +} + ++ (id)newDictionaryWithObjects: (id*)objects + arrayMapping: (id)mapping + zone: (NSZone*)zone +{ + return [self notImplemented: _cmd]; +} + ++ (id)newWithInitializer: (EOMKKDInitializer*)initializer + objects: (id*)objects + zone: (NSZone*)zone +{ + return [[self allocWithZone: zone] initWithInitializer: initializer + objects: objects]; +} + ++ (id)dictionaryWithObjects: (NSArray*)objects + forKeys: (NSArray*)keys +{ + EOMutableKnownKeyDictionary *dict = nil; + int objectsCount = [objects count]; + int keysCount = [keys count]; + + NSAssert2(objectsCount == keysCount, + @"Objects Count (%d) is not equal to keys Count (%d)", + objectsCount, + keysCount); + + if (objectsCount > 0) + { + id objectIds[objectsCount]; + id keyIds[keysCount]; + + [objects getObjects: objectIds]; + [keys getObjects: keyIds]; + + dict = [[[self alloc] initWithObjects: objectIds + forKeys: keyIds + count: objectsCount] autorelease]; + } + + return dict; +} + ++ (EOMKKDInitializer*)initializerFromKeyArray: (NSArray*)keys +{ + return [EOMKKDInitializer initializerFromKeyArray: keys]; +} + ++ (id)newWithInitializer: (EOMKKDInitializer*)initializer +{ + return [self newWithInitializer: initializer + zone: NULL]; +} + ++ (id)newWithInitializer: (EOMKKDInitializer*)initializer + zone: (NSZone*)zone +{ + return [[self allocWithZone: zone] initWithInitializer: initializer]; +} + ++ (id) dictionaryWithInitializer: (EOMKKDInitializer*)initializer +{ + return [[self newWithInitializer: initializer]autorelease]; +} + +- (id) initWithInitializer: (EOMKKDInitializer*)initializer +{ + EOFLOGObjectFnStart(); + + if ((self = [self init])) + { + int count; + + NSAssert(initializer, @"No Initializer"); + EOFLOGObjectLevelArgs(@"EOMKKD", @"suite"); + + ASSIGN(_MKKDInitializer, initializer); + + count = [_MKKDInitializer count]; + EOFLOGObjectLevelArgs(@"EOMKKD", @"count=%d", count); + + _values = NSZoneMalloc([self zone], count * sizeof(id)); + memset(_values, 0, count * sizeof(id)); + } + + EOFLOGObjectFnStop(); + + return self; +} + +- (id) initWithInitializer: (EOMKKDInitializer*)initializer + objects: (id*)objects +{ + EOFLOGObjectFnStart(); + + if ((self = [self initWithInitializer: initializer])) + { + EOFLOGObjectLevelArgs(@"EOMKKD", @"suite objects=%p initializer=%p", + objects, _MKKDInitializer); + + if (objects) + { + int i; + int count = [_MKKDInitializer count]; + + EOFLOGObjectLevelArgs(@"EOMKKD", @"count=%d", count); + + for (i = 0; i < count; i++) + { + EOFLOGObjectLevelArgs(@"EOMKKD", @"%d=%p (old=%p)", + i, objects[i], _values[i]); + ASSIGN(_values[i], objects[i]); + } + } + } + + EOFLOGObjectLevelArgs(@"EOMKKD", @"END"); + + return self; +} + +// This is the designated initializer +- (id) initWithObjects: (id*)objects + forKeys: (id*)keys + count: (unsigned int)count +{ + //OK + EOMKKDInitializer *initializer = nil; + + EOFLOGObjectFnStart(); + + if (count > 0) + { + NSAssert(keys, @"No keys array"); + NSAssert(count > 0, @"No keys"); + + initializer = [[[EOMKKDInitializer alloc] initWithKeys: keys + count: count] autorelease]; + + NSAssert(initializer, @"No Initializer"); + EOFLOGObjectLevelArgs(@"EOMKKD", @"suite"); + + ASSIGN(_MKKDInitializer, initializer); + + _values = NSZoneMalloc([self zone], count * sizeof(id)); + + if (objects) + { + int i; + + for (i = 0; i < count; i++) + { + ASSIGN(_values[i], objects[i]); + } + } + else + { + memset(_values, 0, count * sizeof(id)); + } + } + + return self; +} + +- (void) dealloc +{ + EOFLOGObjectLevelArgs(@"EOMKKD", @"Deallocate EOMKKDDictionary %p", self); + + if (_values) + { + int i; + unsigned int count = [_MKKDInitializer count]; + + for (i = 0; i < count; i++) + { + DESTROY(_values[i]); + } + + NSZoneFree([self zone], _values); + } + + DESTROY(_MKKDInitializer); + DESTROY(_extraData); + + [super dealloc]; +} + +- (unsigned int) count +{ + NSAssert(_MKKDInitializer, @"No _MKKDInitializer"); + return [_MKKDInitializer count]; +} + +- (id) objectForKey: (NSString*)key +{ + id object = nil; + unsigned int index; + +// EOFLOGObjectFnStart(); + NSAssert(_MKKDInitializer, @"No _MKKDInitializer"); + + index = [_MKKDInitializer indexForKey: key]; + +// EOFLOGObjectLevelArgs(@"EOMKKD", @"index=%d", index); + + if (index == NSNotFound) + { + if (_extraData) + object = [_extraData objectForKey: key]; + } + else + { + NSAssert2(index < [_MKKDInitializer count], @"bad index %d (count=%u)", + index, [_MKKDInitializer count]); + object = _values[index]; + } + +// EOFLOGObjectLevelArgs(@"EOMKKD",@"object=%p",object); +// EOFLOGObjectFnStop(); + + return object; +} + +- (void) setObject: (id)object + forKey: (NSString*)key +{ + unsigned int index; + + NSAssert(_MKKDInitializer, @"No _MKKDInitializer"); + + index = [_MKKDInitializer indexForKey: key]; + + if (index == NSNotFound) + { + if (!_extraData) + _extraData = [NSMutableDictionary new]; + + [_extraData setObject: object + forKey: key]; + } + else + { + NSAssert2(index < [_MKKDInitializer count], @"bad index %d (count=%u)", + index, [_MKKDInitializer count]); + + ASSIGN(_values[index], object); + } +} + +- (void) removeObjectForKey: (NSString*)key +{ + unsigned int index; + + NSAssert(_MKKDInitializer, @"No _MKKDInitializer"); + + index = [_MKKDInitializer indexForKey: key]; + + if (index == NSNotFound) + { + if (_extraData) + [_extraData removeObjectForKey: key]; + } + else + { + NSAssert2(index < [_MKKDInitializer count], @"bad index %d (count=%u)", + index, [_MKKDInitializer count]); + + DESTROY(_values[index]); + } +} + +- (BOOL) containsObjectsNotIdenticalTo: (id)object +{ + BOOL result = NO; + int i; + unsigned int count = [_MKKDInitializer count]; + + for (i = 0; !result && i < count; i++) + { + if (_values[i] != object) + { + if (isNilOrEONull(_values[i])) + result =! isNilOrEONull(object); + else if (isNilOrEONull(object)) + result = YES; + else + result = ![_values[i] isEqual: object]; + } + } + + EOFLOGObjectLevelArgs(@"EOMKKD", @"result = %s", (result ? "YES" : "NO")); + + return result; +} + +- (void)addEntriesFromDictionary: (NSDictionary*)dictionary +{ + NSEnumerator *e = [dictionary keyEnumerator]; + id key; + + while ((key = [e nextObject])) + { + if (![self objectForKey: key]) //Don't overwrite already present values ? + { + [self setObject: [dictionary objectForKey: key] + forKey: key]; + } + } +} + +- (NSEnumerator*) keyEnumerator +{ + EOMKKDKeyEnumerator *MKKDEnum; + + MKKDEnum = [[[EOMKKDKeyEnumerator alloc] initWithTarget: self] autorelease]; + + return MKKDEnum; +} + +- (EOMKKDInitializer*) eoMKKDInitializer +{ + return _MKKDInitializer; +} + +- (NSMutableDictionary*)extraData +{ + return _extraData; +} + +- (NSString*)debugDescription +{ + NSString *dscr; + int i; + int count; + id *keys; + + dscr = [NSString stringWithFormat: @"<%s %p - KV=", + object_get_class_name(self), + (void*)self]; + + count = [_MKKDInitializer count]; + keys = [_MKKDInitializer keys]; + + for (i = 0; i < count; i++) + dscr = [dscr stringByAppendingFormat: @"%@=%@\n", keys[i], _values[i]]; + + dscr = [dscr stringByAppendingFormat: @"extraDatas:%@", _extraData]; + dscr = [dscr stringByAppendingString: @">"]; + + return dscr; +} + +- (BOOL)hasKey: (id)key +{ + if ([_MKKDInitializer hasKey: key]) + return YES; + else if ([_extraData objectForKey: key]) + return YES; + else + return NO; +} + +@end diff --git a/EOControl/EONSAddOns.h b/EOControl/EONSAddOns.h new file mode 100644 index 0000000..353f6aa --- /dev/null +++ b/EOControl/EONSAddOns.h @@ -0,0 +1,75 @@ +/* + EONSAddOns.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: October 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EONSAddOns_h__ +#define __EONSAddOns_h__ + +#import + + +@interface NSObject (NSObjectPerformingSelector) +- (NSArray*)resultsOfPerformingSelector: (SEL)sel + withEachObjectInArray: (NSArray*)array; +- (NSArray*)resultsOfPerformingSelector: (SEL)sel + withEachObjectInArray: (NSArray*)array + defaultResult: (id)defaultResult; +@end + +@interface NSArray (NSArrayPerformingSelector) +- (id)firstObject; +- (NSArray*)resultsOfPerformingSelector: (SEL)sel; +- (NSArray*)resultsOfPerformingSelector: (SEL)sel + defaultResult: (id)defaultResult; +- (NSArray*)resultsOfPerformingSelector: (SEL)sel + withObject: (id)obj1; +- (NSArray*)resultsOfPerformingSelector: (SEL)sel + withObject: (id)obj1 + defaultResult: (id)defaultResult; +- (NSArray*)resultsOfPerformingSelector: (SEL)sel + withObject: (id)obj1 + withObject: (id)obj2; +- (NSArray*)resultsOfPerformingSelector: (SEL)sel + withObject: (id)obj1 + withObject: (id)obj2 + defaultResult: (id)defaultResult; +- (NSArray*)arrayExcludingObjectsInArray: (NSArray*)array; +- (NSArray*)arrayExcludingObject: (id)object; +- (NSArray*)arrayByReplacingObject: (id)object1 + withObject: (id)object2; +- (BOOL)containsIdenticalObjectsWithArray: (NSArray*)array; + +@end + +@interface NSObject (EOCompareOnName) +- (NSComparisonResult)eoCompareOnName: (id)object; +@end + +@interface NSString (YorYes) +- (BOOL)isYorYES; +@end + + +#endif /* __EONSAddOns_h__ */ diff --git a/EOControl/EONSAddOns.m b/EOControl/EONSAddOns.m new file mode 100644 index 0000000..45c8d49 --- /dev/null +++ b/EOControl/EONSAddOns.m @@ -0,0 +1,434 @@ +/** + EONSAddOns.m EONSAddOns + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: October 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import + +#import + + +@implementation NSObject (NSObjectPerformingSelector) + +- (NSArray*)resultsOfPerformingSelector: (SEL)sel + withEachObjectInArray: (NSArray*)array +{ + return [self resultsOfPerformingSelector: sel + withEachObjectInArray: array + defaultResult: nil]; +} + +- (NSArray*)resultsOfPerformingSelector: (SEL)sel + withEachObjectInArray: (NSArray*)array + defaultResult: (id)defaultResult +{ + NSMutableArray *results = nil; + + if (array) + { + int i, count = [array count]; + id object = nil; + + results = [NSMutableArray array]; + + //OPTIMIZE + NS_DURING + { + for(i = 0; i < count; i++) + { + id result; + + object = [array objectAtIndex: i]; + result = [self performSelector: sel + withObject: object]; + if (!result) + result = defaultResult; + + NSAssert3(result, + @"%@: No result for object %@ resultOfPerformingSelector:\"%s\" withEachObjectInArray:", + self, + object, + sel_get_name(sel)); + + [results addObject: result]; //TODO What to do if nil ?? + } + } + NS_HANDLER + { + NSWarnLog(@"object %p %@ may not support %@", + object, + [object class], + NSStringFromSelector(sel)); + NSLog(@"%@ (%@)",localException,[localException reason]); + [localException raise]; + } + NS_ENDHANDLER; + } + + return results; +} + +@end + +@implementation NSArray (NSArrayPerformingSelector) + +- (id)firstObject +{ + NSAssert1([self count] > 0, @"no object in %@", self); + return [self objectAtIndex: 0]; +} + +- (NSArray*)resultsOfPerformingSelector: (SEL)sel +{ + return [self resultsOfPerformingSelector: sel + defaultResult: nil]; +} + +- (NSArray*)resultsOfPerformingSelector: (SEL)sel + defaultResult: (id)defaultResult +{ + NSMutableArray *results=[NSMutableArray array]; + int i, count = [self count]; + id object = nil; + + NSDebugMLLog(@"gsdb", @"self:%p (%@) results:%p (%@)", + self, [self class], results, [results class]); + + //OPTIMIZE + NS_DURING + { + for(i = 0; i < count; i++) + { + id result; + + object = [self objectAtIndex: i]; + result = [object performSelector: sel]; + + if (!result) + result = defaultResult; + + NSAssert3(result, + @"%@: No result for object %@ resultOfPerformingSelector:\"%s\"", + self, + object, + sel_get_name(sel)); + + [results addObject: result]; //TODO What to do if nil ?? + } + } + NS_HANDLER + { + NSWarnLog(@"object %p %@ may doesn't support %@", + object, + [object class], + NSStringFromSelector(sel)); + + NSLog(@"%@ (%@)", localException, [localException reason]); + + [localException raise]; + } + NS_ENDHANDLER; + + NSDebugMLLog(@"gsdb", @"self:%p (%@) results:%p (%@)", + self, [self class], results, [results class]); + + return results; +} + +- (NSArray*)resultsOfPerformingSelector: (SEL)sel + withObject: (id)obj1 +{ + return [self resultsOfPerformingSelector: sel + withObject: obj1 + defaultResult: nil]; +} + +- (NSArray*)resultsOfPerformingSelector:(SEL)sel + withObject:(id)obj1 + defaultResult:(id)defaultResult +{ + NSMutableArray *results = [NSMutableArray array]; + int i, count = [self count]; + id object = nil; + + //OPTIMIZE + NS_DURING + { + for(i = 0; i < count; i++) + { + id result; + + object = [self objectAtIndex: i]; + result = [object performSelector: sel + withObject: obj1]; + + if (!result) + result = defaultResult; + + NSAssert3(result, + @"%@: No result for object %@ resultOfPerformingSelector:\"%s\"", + self, + object, + sel_get_name(sel)); + + [results addObject: result]; //TODO What to do if nil ?? + } + } + NS_HANDLER + { + NSWarnLog(@"object %p %@ may doesn't support %@", + object, + [object class], + NSStringFromSelector(sel)); + + NSLog(@"%@ (%@)", localException, [localException reason]); + + [localException raise]; + } + NS_ENDHANDLER; + + return results; +} + +- (NSArray*)resultsOfPerformingSelector: (SEL)sel + withObject: (id)obj1 + withObject: (id)obj2 +{ + return [self resultsOfPerformingSelector: sel + withObject: obj1 + withObject: obj2 + defaultResult: nil]; +} + +- (NSArray*)resultsOfPerformingSelector: (SEL)sel + withObject: (id)obj1 + withObject: (id)obj2 + defaultResult: (id)defaultResult +{ + NSMutableArray *results = [NSMutableArray array]; + int i, count = [self count]; + id object = nil; + + //OPTIMIZE + NS_DURING + { + for(i = 0; i < count; i++) + { + id result; + + object = [self objectAtIndex: i]; + result = [object performSelector: sel + withObject: obj1 + withObject: obj2]; + + if (!result) + result = defaultResult; + + NSAssert3(result, + @"%@: No result for object %@ resultOfPerformingSelector:\"%s\"", + self, + object, + sel_get_name(sel)); + + [results addObject: result]; //TODO What to do if nil ?? + } + } + NS_HANDLER + { + NSWarnLog(@"object %p %@ may doesn't support %@", + object, + [object class], + NSStringFromSelector(sel)); + + NSLog(@"%@ (%@)", localException, [localException reason]); + + [localException raise]; + } + NS_ENDHANDLER; + + return results; +} + +- (NSArray*)arrayExcludingObjectsInArray: (NSArray*)array +{ + //Verify: mutable/non mutable,.. + NSArray *result = nil; + unsigned int selfCount = [self count]; + + if (selfCount > 0) //else return nil + { + unsigned int arrayCount = [array count]; + + if (arrayCount == 0) //Nothing to exclude ? + result = self; + else + { + int i; + + for (i = 0; i < selfCount; i++) + { + id object = [self objectAtIndex: i]; + int index = [array indexOfObjectIdenticalTo: object]; + + if (index == NSNotFound) + { + if (result) + [(NSMutableArray*)result addObject: object]; + else + result = [NSMutableArray arrayWithObject: object]; + } + } + } + } + + return result; +} + +- (NSArray *)arrayExcludingObject: (id)anObject +{ + //Verify: mutable/non mutable,.. + NSArray *result = nil; + unsigned int selfCount = [self count]; + + if (selfCount > 0 && anObject) //else return nil + { + int i; + + for (i = 0; i < selfCount; i++) + { + id object = [self objectAtIndex: i]; + + if (object != anObject) + { + if (result) + [(NSMutableArray *)result addObject: object]; + else + result = [NSMutableArray arrayWithObject: object]; + } + } + } + + return result; +} + +- (NSArray*)arrayByReplacingObject: (id)object1 + withObject: (id)object2 +{ + NSArray *array = nil; + int count; + + count = [self count]; + + if (count > 0) + { + int i; + id o = nil; + NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity: count]; + + for (i = 0; i < count; i++) + { + o = [self objectAtIndex: i]; + + if ([o isEqual: object1]) + [tmpArray addObject: object2]; + else + [tmpArray addObject: o]; + } + + array = [NSArray arrayWithArray: tmpArray]; + } + else + array = self; + + return array; +} + +/** return YES if the 2 arrays contains exactly identical objects (compared by address) (i.e. only the order may change), NO otherwise +**/ +- (BOOL)containsIdenticalObjectsWithArray: (NSArray *)array +{ + BOOL ret = NO; + int selfCount = [self count]; + int arrayCount = [array count]; + + if (selfCount == arrayCount) + { + BOOL foundInArray[arrayCount]; + int i, j; + + memset(foundInArray, 0, sizeof(BOOL) * arrayCount); + ret = YES; + + for (i = 0; ret && i < selfCount; i++) + { + id selfObj = [self objectAtIndex: i]; + + ret = NO; + + for (j = 0; j < arrayCount; j++) + { + id arrayObj = [array objectAtIndex: j]; + + if (arrayObj == selfObj && !foundInArray[j]) + { + foundInArray[j] = YES; + ret = YES; + + break; + } + } + } + } + + return ret; +} + +@end + +@implementation NSObject (EOCompareOnName) + +- (NSComparisonResult)eoCompareOnName: (id)object +{ + return [[self name] compare: [object name]]; +} + +@end + +@implementation NSString (YorYes) + +- (BOOL)isYorYES +{ + return ([self isEqual: @"Y"] || [self isEqual: @"YES"]); +} + +@end diff --git a/EOControl/EONotQualifier.m b/EOControl/EONotQualifier.m new file mode 100644 index 0000000..940d91b --- /dev/null +++ b/EOControl/EONotQualifier.m @@ -0,0 +1,82 @@ +/** + EOOrQualifier.m EOOrQualifier + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import +#import + +#import + +#import + + +@implementation EONotQualifier + ++ (EOQualifier *)qualifierWithQualifier: (EOQualifier *)qualifier +{ + return [[[self alloc] initWithQualifier: qualifier] autorelease]; +} + +- initWithQualifier: (EOQualifier *)qualifier +{ + self = [super init]; + + ASSIGN(_qualifier, qualifier); + + return self; +} + +- (EOQualifier *)qualifier +{ + return _qualifier; +} + +- (id)copyWithZone: (NSZone *)zone +{ + EONotQualifier *qual = [[EONotQualifier alloc] init]; + + qual->_qualifier = [_qualifier copyWithZone: zone]; + + return qual; +} + +- (BOOL)evaluateWithObject: (id)object +{ + //TODO + [self notImplemented: _cmd]; + return NO; +} + +@end diff --git a/EOControl/EONull.h b/EOControl/EONull.h new file mode 100644 index 0000000..77144b9 --- /dev/null +++ b/EOControl/EONull.h @@ -0,0 +1,45 @@ +/* + EONull.h + + Copyright (C) 1996-2002 Free Software Foundation, Inc. + + Author: Mircea Oancea + Date: 1996 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EONull_h__ +#define __EONull_h__ + +#import + +@interface EONull : NSObject ++ null; +@end /* EONull */ + +@interface NSObject (EONull) + +- (BOOL)isEONull; +- (BOOL)isNotEONull; + +@end + +extern BOOL isNilOrEONull(id v); + +#endif /* __EONull_h__ */ diff --git a/EOControl/EONull.m b/EOControl/EONull.m new file mode 100644 index 0000000..e0d856a --- /dev/null +++ b/EOControl/EONull.m @@ -0,0 +1,195 @@ +/** + EONull.m EONull Class + + Copyright (C) 1996-2002 Free Software Foundation, Inc. + + Author: Mircea Oancea + Date: 1996 + + Author: Mirko Viviani + Date: February 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import +#import +#import + + +@implementation EONull + +static EONull *sharedEONull = nil; + +#ifndef FOUNDATION_HAS_KVC + ++ (void)initialize +{ + // THREAD - do this operation under a lock + sharedEONull = (EONull *)NSAllocateObject(self, 0, NSDefaultMallocZone()); +} + ++ null +{ + return sharedEONull; +} + ++ allocWithZone +{ + return sharedEONull; +} + +- copy +{ + return self; +} + +- copyWithZone: (NSZone *)zone +{ + return self; +} + +// One cannot destroy the shared null object + +- (id)retain +{ + return self; +} + +- (id)autorelease +{ + return self; +} + +- (void)release +{ +} + +- (void)dealloc +{ +} + +#else ++ (void)initialize +{ + sharedEONull = (EONull *)[NSNull null]; +} + ++ null +{ + return sharedEONull; +} + ++ allocWithZone +{ + return sharedEONull; +} + +- copy +{ + return sharedEONull; +} + +- copyWithZone: (NSZone *)zone +{ + return sharedEONull; +} + +- (id)retain +{ + return sharedEONull; +} + +- (id)autorelease +{ + return sharedEONull; +} + +- (void)release +{ +} + +- (void)dealloc +{ +} + +// OK +- (id)valueForKey: (NSString *)key +{ + return self; +} + +#endif + +- (NSString *)sqlString +{ + EOFLOGObjectFnStart(); + EOFLOGObjectFnStop(); + return @"NULL"; +} + +@end /* EONull */ + +#ifdef FOUNDATION_HAS_KVC +@implementation NSNull (EOSQLFormatting) + +- (NSString *)sqlString +{ + EOFLOGObjectFnStart(); + EOFLOGObjectFnStop(); + + return @"NULL"; +} + +- (id)valueForKey:(NSString *)key +{ + return self; +}; + +@end +#endif + + +@implementation NSObject (EONull) + +- (BOOL)isEONull +{ + return (((id)self) == sharedEONull || (((id)self) == [NSNull null])); +} + +- (BOOL)isNotEONull +{ + return ![self isEONull]; +} + +@end + +BOOL isNilOrEONull(id v) +{ + return ((!v) || [v isEONull]); +} diff --git a/EOControl/EOObjectStore.h b/EOControl/EOObjectStore.h new file mode 100644 index 0000000..62af738 --- /dev/null +++ b/EOControl/EOObjectStore.h @@ -0,0 +1,90 @@ +/* + EOObjectStore.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: June 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOObjectStore_h__ +#define __EOObjectStore_h__ + +#import + +@class EOEditingContext; +@class EOGlobalID; +@class EOFetchSpecification; + + +@interface EOObjectStore : NSObject + +- (id)faultForGlobalID: (EOGlobalID *)globalID + editingContext: (EOEditingContext *)context; + +- (id)faultForRawRow: (NSDictionary *)row + entityNamed: (NSString *)entityName + editingContext: (EOEditingContext *)context; + +- (NSArray *)arrayFaultWithSourceGlobalID: (EOGlobalID *)globalID + relationshipName: (NSString *)name + editingContext: (EOEditingContext *)context; + +- (void)initializeObject: (id)object + withGlobalID: (EOGlobalID *)globalID + editingContext: (EOEditingContext *)context; + +- (NSArray *)objectsForSourceGlobalID: (EOGlobalID *)globalID + relationshipName: (NSString *)name + editingContext: (EOEditingContext *)context; + +- (void)refaultObject: object + withGlobalID: (EOGlobalID *)globalID + editingContext: (EOEditingContext *)context; + +- (void)saveChangesInEditingContext: (EOEditingContext *)context; + +- (NSArray *)objectsWithFetchSpecification: (EOFetchSpecification *)fetchSpecification + editingContext: (EOEditingContext *)context; + +- (BOOL)isObjectLockedWithGlobalID: (EOGlobalID *)gid + editingContext: (EOEditingContext *)context; + +- (void)lockObjectWithGlobalID: (EOGlobalID *)gid + editingContext: (EOEditingContext *)context; + +- (void)invalidateAllObjects; +- (void)invalidateObjectsWithGlobalIDs: (NSArray *)globalIDs; + +- (id) propertiesForObjectWithGlobalID: (EOGlobalID *)gid + editingContext: (EOEditingContext *)context; +@end + + +extern NSString *EOObjectsChangedInStoreNotification; + +extern NSString *EOInvalidatedAllObjectsInStoreNotification; + +extern NSString *EODeletedKey; +extern NSString *EOInsertedKey; +extern NSString *EOInvalidatedKey; +extern NSString *EOUpdatedKey; + +#endif diff --git a/EOControl/EOObjectStore.m b/EOControl/EOObjectStore.m new file mode 100644 index 0000000..9e2a07a --- /dev/null +++ b/EOControl/EOObjectStore.m @@ -0,0 +1,138 @@ +/** + EOObjectStore.m EOObjectStore + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: June 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import + + +NSString *EOObjectsChangedInStoreNotification = @"EOObjectsChangedInStoreNotification"; + +NSString *EOInvalidatedAllObjectsInStoreNotification = @"EOInvalidatedAllObjectsInStoreNotification"; + +NSString *EODeletedKey = @"inserted"; +NSString *EOInsertedKey = @"deleted"; +NSString *EOInvalidatedKey = @"updated"; +NSString *EOUpdatedKey = @"invalidated"; + + +@implementation EOObjectStore + +- (id)faultForGlobalID: (EOGlobalID *)globalID + editingContext: (EOEditingContext *)context +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +- (id)faultForRawRow: (NSDictionary *)row + entityNamed: (NSString *)entityName + editingContext: (EOEditingContext *)context +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +- (NSArray *)arrayFaultWithSourceGlobalID: (EOGlobalID *)globalID + relationshipName: (NSString *)name + editingContext: (EOEditingContext *)context +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +- (void)initializeObject: (id)object + withGlobalID: (EOGlobalID *)globalID + editingContext: (EOEditingContext *)context +{ + [self subclassResponsibility: _cmd]; +} + +- (NSArray *)objectsForSourceGlobalID: (EOGlobalID *)globalID + relationshipName: (NSString *)name + editingContext: (EOEditingContext *)context +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +- (void)refaultObject: object + withGlobalID: (EOGlobalID *)globalID + editingContext: (EOEditingContext *)context +{ + [self subclassResponsibility: _cmd]; +} + +- (void)saveChangesInEditingContext: (EOEditingContext *)context +{ + [self subclassResponsibility: _cmd]; +} + +- (NSArray *)objectsWithFetchSpecification: (EOFetchSpecification *)fetchSpecification + editingContext: (EOEditingContext *)context +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +- (BOOL)isObjectLockedWithGlobalID: (EOGlobalID *)gid + editingContext: (EOEditingContext *)context +{ + [self subclassResponsibility: _cmd]; + return NO; +} + +- (void)lockObjectWithGlobalID: (EOGlobalID *)gid + editingContext: (EOEditingContext *)context +{ + [self subclassResponsibility: _cmd]; +} + +- (void)invalidateAllObjects +{ + [self subclassResponsibility: _cmd]; +} + +- (void)invalidateObjectsWithGlobalIDs: (NSArray *)globalIDs +{ + [self subclassResponsibility: _cmd]; +} + +- (id) propertiesForObjectWithGlobalID: (EOGlobalID *)gid + editingContext: (EOEditingContext *)context +{ + return [self subclassResponsibility:_cmd]; +} + +@end diff --git a/EOControl/EOObjectStoreCoordinator.h b/EOControl/EOObjectStoreCoordinator.h new file mode 100644 index 0000000..bfacf68 --- /dev/null +++ b/EOControl/EOObjectStoreCoordinator.h @@ -0,0 +1,108 @@ +/* + EOObjectStoreCoordinator.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Date: June 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOObjectStoreCoordinator_h__ +#define __EOObjectStoreCoordinator_h__ + +#import +#import + +@class EOCooperatingObjectStore; +@class EOQualifier; +@class EOModelGroup; + +@interface EOObjectStoreCoordinator:EOObjectStore +{ + NSMutableArray *_stores; + NSDictionary *_userInfo; +} + +- init; + +- (void)addCooperatingObjectStore: (EOCooperatingObjectStore *)store; + +- (void)removeCooperatingObjectStore: (EOCooperatingObjectStore *)store; + +- (NSArray *)cooperatingObjectStores; + +- (void)forwardUpdateForObject: object changes: (NSDictionary *)changes; + +- (NSDictionary *)valuesForKeys: (NSArray *)keys object: object; + +- (EOCooperatingObjectStore *)objectStoreForGlobalID: (EOGlobalID *)gloablID; + +- (EOCooperatingObjectStore *)objectStoreForObject: object; + +- (EOCooperatingObjectStore *)objectStoreForFetchSpecification: (EOFetchSpecification *)fetchSpecification; + +- (NSDictionary *)userInfo; +- (void)setUserInfo: (NSDictionary *)info; + ++ (void)setDefaultCoordinator: (EOObjectStoreCoordinator *)coordinator; ++ (id)defaultCoordinator; + +@end + +@interface EOObjectStoreCoordinator (EOModelGroup) + +- (id) modelGroup; +- (void) setModelGroup: (EOModelGroup*)modelGroup; + +@end + +// Notifications: +extern NSString *EOCooperatingObjectStoreWasAdded; +extern NSString *EOCooperatingObjectStoreWasRemoved; + +extern NSString *EOCooperatingObjectStoreNeeded; + + +@interface EOCooperatingObjectStore:EOObjectStore + +- (BOOL)ownsGlobalID: (EOGlobalID *)globalID; + +- (BOOL)ownsObject: (id)object; + +- (BOOL)ownsEntityNamed: (NSString *)entityName; + +- (BOOL)handlesFetchSpecification: (EOFetchSpecification *)fetchSpecification; + +- (void)prepareForSaveWithCoordinator: (EOObjectStoreCoordinator *)coordinator editingContext:(EOEditingContext *)context; + +- (void)recordChangesInEditingContext; + +- (void)recordUpdateForObject:object changes: (NSDictionary *)changes; + +- (void)performChanges; + +- (void)commitChanges; +- (void)rollbackChanges; + +- (NSDictionary *)valuesForKeys: (NSArray *)keys object: object; + +@end + + +#endif diff --git a/EOControl/EOObjectStoreCoordinator.m b/EOControl/EOObjectStoreCoordinator.m new file mode 100644 index 0000000..276c99b --- /dev/null +++ b/EOControl/EOObjectStoreCoordinator.m @@ -0,0 +1,628 @@ +/** + EOObjectStoreCoordinator.m EOObjectStoreCoordinator + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Date: June 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import + +#import + +#import +#import + + +@implementation EOObjectStoreCoordinator + + +static EOObjectStoreCoordinator *defaultCoordinator = nil; + +NSString *EOCooperatingObjectStoreWasAdded = @"EOCooperatingObjectStoreWasAdded"; +NSString *EOCooperatingObjectStoreWasRemoved = @"EOCooperatingObjectStoreWasRemoved"; +NSString *EOCooperatingObjectStoreNeeded = @"EOCooperatingObjectStoreNeeded"; + + +- init +{ + self = [super init]; + + _stores = [NSMutableArray new]; + + return self; +} + +- (void)dealloc +{ + NSDebugMLog(@"dealloc coordinator"); + DESTROY(_stores); + DESTROY(_userInfo); + + [super dealloc]; + NSDebugMLog(@"dealloc coordinator end"); +} + +- (void)addCooperatingObjectStore: (EOCooperatingObjectStore *)store +{ + if ([_stores containsObject:store] == NO) + { + [_stores addObject:store]; + + [[NSNotificationCenter defaultCenter] + postNotificationName: EOCooperatingObjectStoreWasAdded + object: store]; + [[NSNotificationCenter defaultCenter] + addObserver: self + selector: @selector(_objectsChangedInSubStore:) + name: EOObjectsChangedInStoreNotification + object: store]; + [[NSNotificationCenter defaultCenter] + addObserver: self + selector: @selector(_invalidatedAllObjectsInSubStore:) + name: EOInvalidatedAllObjectsInStoreNotification + object: store]; + } +} + +- (void)removeCooperatingObjectStore: (EOCooperatingObjectStore *)store +{ + if ([_stores containsObject:store] == YES) + { + [_stores removeObject: store]; + + [[NSNotificationCenter defaultCenter] + postNotificationName: EOCooperatingObjectStoreWasRemoved + object: store]; + //ODO remove aboservers + } +} + +- (NSArray *)cooperatingObjectStores +{ + return _stores; +} + +- (void)forwardUpdateForObject: object + changes: (NSDictionary *)changes +{ + [[self objectStoreForObject: object] + recordUpdateForObject: object changes: changes]; +} + +- (NSDictionary *)valuesForKeys: (NSArray *)keys + object: object +{ + return [[self objectStoreForObject: object] + valuesForKeys:keys object: object]; +} + +- (void) requestStoreForGlobalID: (EOGlobalID *)globalID + fetchSpecification: (id)param1 + object: (id)object +{ + //TODO if object!=nil or fetchsec !=nil + [[NSNotificationCenter defaultCenter] + postNotificationName: EOCooperatingObjectStoreNeeded + object: self + userInfo: [NSDictionary dictionaryWithObject: globalID + forKey: @"globalID"]]; + +} + +- (EOCooperatingObjectStore*)objectStoreForGlobalID: (EOGlobalID *)globalID +{ + EOCooperatingObjectStore *store = nil; + NSEnumerator *storeEnum = nil; + int num = 2; + + while (num) + { + storeEnum = [_stores objectEnumerator]; + + while ((store = [storeEnum nextObject])) + if ([store ownsGlobalID: globalID] == YES) + return store; + + NSDebugMLLog(@"gsdb", @"num=%d", num); + + if(--num) + [self requestStoreForGlobalID: globalID + fetchSpecification: nil + object: nil]; + } + + return nil; +} + +- (EOCooperatingObjectStore *)objectStoreForObject: object +{ + EOCooperatingObjectStore *store; + NSEnumerator *storeEnum; + int num = 2; + + while (num) + { + storeEnum = [_stores objectEnumerator]; + + while ((store = [storeEnum nextObject])) + if ([store ownsObject: object] == YES) + return store; + + NSDebugMLLog(@"gsdb", @"num=%d", num); + + if(--num) + [[NSNotificationCenter defaultCenter] + postNotificationName: EOCooperatingObjectStoreNeeded + object: self + userInfo: [NSDictionary dictionaryWithObject: object + forKey: @"object"]]; + } + + return nil; +} + +- (EOCooperatingObjectStore *)objectStoreForFetchSpecification: (EOFetchSpecification *)fetchSpecification +{ + EOCooperatingObjectStore *store = nil; + NSEnumerator *storeEnum = nil; + int num = 2; + + while (num) + { + storeEnum = [_stores objectEnumerator]; + + while ((store = [storeEnum nextObject])) + if ([store handlesFetchSpecification: fetchSpecification] == YES) + return store; + + NSDebugMLLog(@"gsdb", @"num=%d", num); + + if(--num) + [[NSNotificationCenter defaultCenter] + postNotificationName: EOCooperatingObjectStoreNeeded + object: self + userInfo: [NSDictionary dictionaryWithObject: fetchSpecification + forKey: @"fetchSpecification"]]; + } + + return nil; +} + +- (NSDictionary *)userInfo +{ + return _userInfo; +} + +- (void)setUserInfo: (NSDictionary *)info +{ + ASSIGN(_userInfo, info); +} + + +// TODO THREADS + ++ (void)setDefaultCoordinator: (EOObjectStoreCoordinator *)coordinator +{ + if (defaultCoordinator) + DESTROY(defaultCoordinator); + + ASSIGN(defaultCoordinator, coordinator); +} + ++ (id)defaultCoordinator +{ + if (defaultCoordinator == nil) + defaultCoordinator = [EOObjectStoreCoordinator new]; + + return defaultCoordinator; +} + + +// EOObjectStore methods +- (id)faultForGlobalID: (EOGlobalID *)globalID + editingContext: (EOEditingContext *)context +{ + id fault = nil; + EOCooperatingObjectStore *objectStore = [self objectStoreForGlobalID: + globalID]; + + if (objectStore) + { + fault = [objectStore faultForGlobalID: globalID + editingContext: context]; + } + + return fault; +} + +- (NSArray *)arrayFaultWithSourceGlobalID: (EOGlobalID *)globalID + relationshipName: (NSString *)name + editingContext: (EOEditingContext *)context +{ + return [[self objectStoreForGlobalID: globalID] + arrayFaultWithSourceGlobalID: globalID + relationshipName: name + editingContext: context]; +} + +- (NSArray *)objectsForSourceGlobalID: (EOGlobalID *)globalID + relationshipName: (NSString *)name + editingContext: (EOEditingContext *)context +{ + return [[self objectStoreForGlobalID: globalID] + objectsForSourceGlobalID: globalID + relationshipName: name + editingContext: context]; +} + +- (void)refaultObject: object + withGlobalID: (EOGlobalID *)globalID + editingContext: (EOEditingContext *)context +{ + [[self objectStoreForGlobalID: globalID] + refaultObject: object + withGlobalID: globalID + editingContext: context]; +} + +- (void)initializeObject: (id)object + withGlobalID: (EOGlobalID *)globalID + editingContext: (EOEditingContext *)context +{ + EOCooperatingObjectStore *objectStore = [self objectStoreForGlobalID: + globalID]; + + [objectStore initializeObject: object + withGlobalID: globalID + editingContext: context]; +} + +- (void)saveChangesInEditingContext: (EOEditingContext *)context +{ + NSArray *insertedObjects; + EOCooperatingObjectStore *objectStore = nil; + NSException *exception = nil; + int i, count; + + EOFLOGObjectFnStart(); + + insertedObjects = [context insertedObjects]; + count = [insertedObjects count]; + +//TODO for inserted: verify + + for (i = 0; i < count; i++) + { + id object = [insertedObjects objectAtIndex: i]; + + objectStore = [self objectStoreForObject: object]; + //SO WHAT //TODO + } + + count = [_stores count]; + + for (i = 0; i < count; i++) + { + objectStore = [_stores objectAtIndex: i]; + + if ([objectStore respondsToSelector: @selector(lock)] == YES) + [(id)objectStore lock]; + } + + NS_DURING + { + count = [_stores count]; + + for (i = 0; i < count; i++) + { + objectStore = [_stores objectAtIndex: i]; + [objectStore prepareForSaveWithCoordinator: self + editingContext: context]; + } + + count = [_stores count]; + + for (i = 0; i < count; i++) + { + // Contructs a list of EODatabaseOperations for all changes in the EditingContext + objectStore = [_stores objectAtIndex: i]; + [objectStore recordChangesInEditingContext]; + } + + NS_DURING + { + count = [_stores count]; + + for (i = 0; i < count; i++) + { + objectStore = [_stores objectAtIndex: i]; + [objectStore performChanges]; + } + + count = [_stores count]; + + for (i = 0; i < count; i++) + { + objectStore = [_stores objectAtIndex: i]; + [objectStore commitChanges]; + } + } + NS_HANDLER + { + NSDebugMLog(@"Exception: %@", localException); + + exception = localException; + count = [_stores count]; + + for (i = 0; i < count; i++) + { + NS_DURING + { + [objectStore rollbackChanges]; + } + NS_HANDLER + { + NSEmitTODO(); + NSDebugMLog(@"Exception in exception: %@", localException); + NSLog(@"Exception in exception: %@", localException); + } + NS_ENDHANDLER; + } + } + NS_ENDHANDLER; + } + NS_HANDLER + { + exception = localException; + } + NS_ENDHANDLER; + + count = [_stores count]; + + for (i = 0; i < count; i++) + { + objectStore = [_stores objectAtIndex: i]; + + if ([objectStore respondsToSelector: @selector(unlock)] == YES) + [(id)objectStore unlock]; + } + + if (exception) + [exception raise]; + + EOFLOGObjectFnStop(); +} + +- (NSArray *)objectsWithFetchSpecification: (EOFetchSpecification *)fetch + editingContext: (EOEditingContext *)context +{ + EOCooperatingObjectStore *objectStore = + [self objectStoreForFetchSpecification: fetch]; + + return [objectStore objectsWithFetchSpecification: fetch + editingContext: context]; +} + +- (void) _invalidatedAllObjectsInSubStore: (NSNotification*)notification +{ + [self notImplemented: _cmd]; //TODO +} + +- (void) _objectsChangedInSubStore: (NSNotification*)notification +{ + EOFLOGObjectFnStart(); //TODO + + if ([notification object] != self) + { + [[NSNotificationCenter defaultCenter] + postNotificationName: EOObjectsChangedInStoreNotification + object: self + userInfo: [notification userInfo]]; //call _objectsChangedInStore: # EditingContext + } + + EOFLOGObjectFnStop(); +} + +- (void)invalidateAllObjects +{ + EOCooperatingObjectStore *store; + NSEnumerator *storeEnum; + + EOFLOGObjectFnStart(); + + storeEnum = [_stores objectEnumerator]; + + while ((store = [storeEnum nextObject])) + [store invalidateAllObjects]; + + EOFLOGObjectFnStop(); +} + +- (void)invalidateObjectsWithGlobalIDs: (NSArray *)globalIDs +{ + NSMutableArray *buf; + NSMutableArray *gids, *gidsToRemove; + NSEnumerator *gidEnum; + EOCooperatingObjectStore *store; + EOGlobalID *gid; + + EOFLOGObjectFnStart(); + + buf = [NSMutableArray arrayWithArray: globalIDs]; + gids = [NSMutableArray arrayWithCapacity: [globalIDs count]]; + gidsToRemove = [NSMutableArray arrayWithCapacity: 16]; + + while (YES) + { + if (![buf count]) + break; + + store = nil; + + gidEnum = [buf objectEnumerator]; + while ((gid = [gidEnum nextObject])) + { + if (store == nil) + { + if ((store = [self objectStoreForGlobalID: gid]) == nil) + [buf addObject: gid]; + } + else if ([store ownsGlobalID: gid] == YES) + [gids addObject: gid]; + } + + [store invalidateObjectsWithGlobalIDs: gids]; + + [buf removeObjectsInArray: gids]; + [buf removeObjectsInArray: gidsToRemove]; + [gids removeAllObjects]; + [gidsToRemove removeAllObjects]; + } + + EOFLOGObjectFnStop(); +} + +@end + +@implementation EOObjectStoreCoordinator (EOModelGroup) + +- (id) modelGroup +{ + //Seems OK + EOModelGroup *modelGroup; + NSDictionary *userInfo; + + EOFLOGObjectFnStart(); + + userInfo = [self userInfo]; + modelGroup = [userInfo objectForKey: @"EOModelGroup"]; + + if (!modelGroup) + { + modelGroup = [EOModelGroup defaultGroup]; + [self setModelGroup: modelGroup]; + } + + EOFLOGObjectFnStop(); + + return modelGroup; +} + +- (void) setModelGroup: (EOModelGroup*)modelGroup +{ + NSMutableDictionary *userInfo; + + EOFLOGObjectFnStart(); + + userInfo = [self userInfo]; + + if (userInfo) + [userInfo setObject: modelGroup + forKey: @"EOModelGroup"]; + else + { + userInfo = [NSMutableDictionary dictionary]; + + [userInfo setObject: modelGroup + forKey: @"EOModelGroup"]; + [self setUserInfo: userInfo]; + } + + EOFLOGObjectFnStop(); +} + +@end + +@implementation EOCooperatingObjectStore + +- (BOOL)ownsGlobalID: (EOGlobalID *)globalID +{ + [self subclassResponsibility: _cmd]; + return NO; +} + +- (BOOL)ownsObject: (id)object +{ + [self subclassResponsibility: _cmd]; + return NO; +} + +- (BOOL)ownsEntityNamed: (NSString *)entityName +{ + [self subclassResponsibility: _cmd]; + return NO; +} + +- (BOOL)handlesFetchSpecification: (EOFetchSpecification *)fetchSpecification +{ + [self subclassResponsibility: _cmd]; + return NO; +} + +- (void)prepareForSaveWithCoordinator: (EOObjectStoreCoordinator *)coordinator + editingContext: (EOEditingContext *)context +{ + [self subclassResponsibility: _cmd]; +} + +- (void)recordChangesInEditingContext +{ + [self subclassResponsibility: _cmd]; +} + +- (void)recordUpdateForObject: object + changes: (NSDictionary *)changes +{ + [self subclassResponsibility: _cmd]; +} + +- (void)performChanges +{ + [self subclassResponsibility: _cmd]; +} + +- (void)commitChanges +{ + [self subclassResponsibility: _cmd]; +} + +- (void)rollbackChanges +{ + [self subclassResponsibility: _cmd]; +} + +- (NSDictionary *)valuesForKeys: (NSArray *)keys + object: object +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +@end diff --git a/EOControl/EOObserver.h b/EOControl/EOObserver.h new file mode 100644 index 0000000..0d094e8 --- /dev/null +++ b/EOControl/EOObserver.h @@ -0,0 +1,138 @@ +/* + EOObserver.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: June 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOObserver_h__ +#define __EOObserver_h__ + +#import + +@interface NSObject (EOObserver) + +- (void)willChange; + +@end + +@protocol EOObserving +- (void)objectWillChange: (id)subject; + +@end + +@interface EOObserverCenter : NSObject + ++ (void)addObserver: (id )observer forObject: (id)object; + ++ (void)removeObserver: (id )observer forObject: (id)object; + ++ (void)notifyObserversObjectWillChange: (id)object; + ++ (NSArray *)observersForObject: (id)object; + ++ (id)observerForObject: (id)object ofClass: (Class)targetClass; + ++ (void)suppressObserverNotification; ++ (void)enableObserverNotification; + ++ (unsigned)observerNotificationSuppressCount; + ++ (void)addOmniscientObserver: (id )observer; ++ (void)removeOmniscientObserver: (id )observer; + +@end + + +@class EODelayedObserverQueue; + +typedef enum { + EOObserverPriorityImmediate, + EOObserverPriorityFirst, + EOObserverPrioritySecond, + EOObserverPriorityThird, + EOObserverPriorityFourth, + EOObserverPriorityFifth, + EOObserverPrioritySixth, + EOObserverPriorityLater +} EOObserverPriority; +#define EOObserverNumberOfPriorities ((unsigned)EOObserverPriorityLater + 1) + + +@interface EODelayedObserver : NSObject { + @public + EODelayedObserver *_next; // linked list. Nil if not on list. +} + +- (void)objectWillChange: (id)subject; + +- (EOObserverPriority)priority; + +- (EODelayedObserverQueue *)observerQueue; + +// Must be implemented by subclasses +- (void)subjectChanged; + +- (void)discardPendingNotification; + +@end + +// used with NSRunLoop's performSelector:target:argument:order:modes: +enum { + EOFlushDelayedObserversRunLoopOrdering = 400000 +}; + + +@interface EODelayedObserverQueue : NSObject +{ + EODelayedObserver *_queue[EOObserverNumberOfPriorities]; // lists for each priority + unsigned _highestNonEmptyQueue; + BOOL _haveEntryInNotificationQueue; + NSArray *_modes; +} + ++ (EODelayedObserverQueue *)defaultObserverQueue; + +- (void)enqueueObserver: (EODelayedObserver *)observer; +- (void)dequeueObserver: (EODelayedObserver *)observer; + +- (void)notifyObserversUpToPriority: (EOObserverPriority)lastPriority; + +- (void)setRunLoopModes: (NSArray *)modes; +- (NSArray *)runLoopModes; + +@end + + +@interface EOObserverProxy : EODelayedObserver { + id _target; + SEL _action; + EOObserverPriority _priority; +} + +- initWithTarget: (id)target + action: (SEL)action + priority: (EOObserverPriority)priority; + +@end + +#endif diff --git a/EOControl/EOObserver.m b/EOControl/EOObserver.m new file mode 100644 index 0000000..9bf3bd4 --- /dev/null +++ b/EOControl/EOObserver.m @@ -0,0 +1,219 @@ +/** + EOObserver.m EOObserver + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: June 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import +#import + +#import +#import +#import +#import +#import + +@implementation NSObject (EOObserver) + +- (void)willChange +{ + EOFLOGObjectFnStart(); + + EOFLOGObjectLevelArgs(@"EOObserver", @"willChange self=%p", self); + [EOObserverCenter notifyObserversObjectWillChange: self]; + + EOFLOGObjectFnStop(); +} + +@end + + +@implementation EOObserverCenter + +static NSMapTable *observersMap = NULL; +static NSMutableArray *omniscientObservers=nil; +static unsigned int notificationSuppressCount=0; +static id lastObject; + + ++ (void)initialize +{ + observersMap = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks, //No because it de-fault observed objects NSObjectMapKeyCallBacks, + NSObjectMapValueCallBacks, + 32); + + omniscientObservers = [NSMutableArray new]; + lastObject = nil; + + notificationSuppressCount = 0; +} + ++ (void)addObserver: (id )observer forObject: (id)object +{ + NSMutableArray *observersArray; + + observersArray = NSMapGet(observersMap, object); + + if (observersArray == nil) + { + observersArray = [NSMutableArray arrayWithCapacity: 16]; + [observersArray addObject: observer]; + + RETAIN(object); //because not owned by observersMap + NSMapInsert(observersMap, object, observersArray); + } + else + { + if ([observersArray containsObject: observer] == NO) + [observersArray addObject: observer]; + } +} + ++ (void)removeObserver: (id )observer forObject: (id)object +{ + NSMutableArray *observersArray; + + observersArray = NSMapGet(observersMap, object); + + if (observersArray) + { + [observersArray removeObject: observer]; + + if (![observersArray count]) + { + NSMapRemove(observersMap, object); + RELEASE(object); //because not owned by observersMap + } + } +} + ++ (void)notifyObserversObjectWillChange: (id)object +{ + EOFLOGClassFnStart(); + + EOFLOGObjectLevelArgs(@"EOObserver", @"object=%p", object); + + if (!notificationSuppressCount) + { + //EOFLOGObjectLevelArgs(@"EOObserver", @"object=%p", object); + EOFLOGObjectLevelArgs(@"EOObserver", @"object=%p lastObject=%p", + object, lastObject); + + if (object == nil) + lastObject = nil; + else if (lastObject != object) + { + NSMutableArray *observersArray; + NSEnumerator *obsEnum; + id observer; + + lastObject = object; + + observersArray = NSMapGet(observersMap, object); + + EOFLOGObjectLevelArgs(@"EOObserver", @"observersArray count=%d", + [observersArray count]); + + obsEnum = [observersArray objectEnumerator]; + while ((observer = [obsEnum nextObject])) + [observer objectWillChange: object]; + + EOFLOGObjectLevelArgs(@"EOObserver", @"omniscientObservers count=%d", + [omniscientObservers count]); + + obsEnum = [omniscientObservers objectEnumerator]; + while ((observer = [obsEnum nextObject])) + [observer objectWillChange: nil]; + } + } + + EOFLOGClassFnStop(); +} + ++ (NSArray *)observersForObject: (id)object +{ + return NSMapGet(observersMap, object); +} + ++ (id)observerForObject: (id)object ofClass: (Class)targetClass +{ + NSArray *observersArray; + + observersArray = NSMapGet(observersMap, object); + + if (observersArray) + { + NSEnumerator *obsEnum; + id observer; + + obsEnum = [observersArray objectEnumerator]; + while ((observer = [obsEnum nextObject])) + if ([observer isKindOfClass: targetClass]) + return observer; + } + + return nil; +} + ++ (void)suppressObserverNotification +{ + notificationSuppressCount++; +} + ++ (void)enableObserverNotification +{ + if (notificationSuppressCount) + notificationSuppressCount--; + else + { + NSLog(@"enableObserverNotification called more than suppressObserverNotification"); + } +} + ++ (unsigned int)observerNotificationSuppressCount +{ + return notificationSuppressCount; +} + ++ (void)addOmniscientObserver: (id )observer +{ + if ([omniscientObservers containsObject: observer] == NO) + [omniscientObservers addObject: observer]; +} + ++ (void)removeOmniscientObserver: (id )observer +{ + [omniscientObservers removeObject: observer]; +} + +@end diff --git a/EOControl/EOOrQualifier.m b/EOControl/EOOrQualifier.m new file mode 100644 index 0000000..80dcb17 --- /dev/null +++ b/EOControl/EOOrQualifier.m @@ -0,0 +1,193 @@ +/** + EOOrQualifier.m EOOrQualifier + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import +#import +#import + +#import +#import + +#import + + +@implementation EOOrQualifier + ++ (EOQualifier *)qualifierWithQualifierArray: (NSArray *)array +{ + return [[[self alloc] initWithQualifierArray: array] autorelease]; +} + ++ (EOQualifier *)qualifierWithQualifiers: (EOQualifier *)qualifiers, ... +{ + NSMutableArray *qualArray = [NSMutableArray array]; + EOQualifier *tmpId; + va_list ap; + + va_start(ap, qualifiers); + + for (tmpId = qualifiers; tmpId != nil;) + { + [qualArray addObject: tmpId]; + tmpId = va_arg(ap, id); + } + + va_end(ap); + + return [[[self alloc] initWithQualifierArray: qualArray] autorelease]; +} + +- initWithQualifiers: (EOQualifier *)qualifiers, ... +{ + if ((self = [super init])) + { + va_list ap; + id tmpId; + NSMutableArray *qualArray = [NSMutableArray array]; + + va_start(ap, qualifiers); + + [qualArray addObject: qualifiers]; + + for (tmpId = va_arg(ap, id); tmpId != nil; tmpId = va_arg(ap, id)) + [qualArray addObject: va_arg(ap, id)]; + + va_end(ap); + + ASSIGN(_qualifiers, qualArray); + } + + return self; +} + +- initWithQualifierArray: (NSArray *)array +{ + if ((self = [super init])) + { + ASSIGNCOPY(_qualifiers, array); + } + + return self; +} + +- (void)dealloc +{ + DESTROY(_qualifiers); + + [super dealloc]; +} + +- (NSArray *)qualifiers +{ + return _qualifiers; +} + +- (id)copyWithZone: (NSZone *)zone +{ + EOOrQualifier *qual = [[EOOrQualifier allocWithZone: zone] init]; + + qual->_qualifiers = [_qualifiers copyWithZone: zone]; + + return qual; +} + +- (BOOL)evaluateWithObject: (id)object +{ + NSEnumerator *qualifiersEnum; + EOQualifier *qualifier; + + qualifiersEnum = [_qualifiers objectEnumerator]; + while ((qualifier = [qualifiersEnum nextObject])) + { + if ([qualifier evaluateWithObject: object] == NO) + return NO; + } + + return YES; +} + +- (id) qualifierMigratedFromEntity: (id)param0 + relationshipPath: (id)param1 +{ + return [self notImplemented: _cmd]; //TODO +} + +- (void) _addBindingsToDictionary: (id)param0 +{ + [self notImplemented: _cmd]; //TODO +} + +- (EOQualifier *) qualifierWithBindings: (NSDictionary *)bindings + requiresAllVariables: (BOOL)requiresAllVariables +{ + EOFLOGObjectLevelArgs(@"EOQualifier", @"bindings=%@", bindings); + + if ([bindings count] > 0) + { + NSEmitTODO(); + return [self notImplemented: _cmd]; //TODO + } + else + return self; +} + +- (id) initWithKeyValueUnarchiver: (id)param0 +{ + return [self notImplemented: _cmd]; //TODO +} + +- (void) encodeWithKeyValueArchiver: (id)param0 +{ + [self notImplemented: _cmd]; //TODO +} + +- (id) validateKeysWithRootClassDescription: (id)param0 +{ + return [self notImplemented: _cmd]; //TODO +} + +- (id) description +{ + NSString *dscr; + + dscr = [NSString stringWithFormat: @"<%s %p - qualifiers: %@>", + object_get_class_name(self), + (void*)self, + _qualifiers]; + return dscr; +} + +@end diff --git a/EOControl/EOQualifier.h b/EOControl/EOQualifier.h new file mode 100644 index 0000000..e2c89f4 --- /dev/null +++ b/EOControl/EOQualifier.h @@ -0,0 +1,230 @@ +/* + EOQualifier.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOQualifier_h__ +#define __EOQualifier_h__ + +#import +#import + + +@class EOClassDescription; +@class EOSQLExpression; +@class EOQualifier; +@class EOEntity; + + +@interface EOQualifier : NSObject +{ +} + ++ (EOQualifier *)qualifierWithQualifierFormat: (NSString *)qualifierFormat, ...; + ++ (EOQualifier *)qualifierWithQualifierFormat: (NSString *)format + arguments: (NSArray *)args; + ++ (EOQualifier *)qualifierWithQualifierFormat: (NSString *)format + varargList: (va_list)args; + ++ (EOQualifier *)qualifierToMatchAllValues: (NSDictionary *)values; ++ (EOQualifier *)qualifierToMatchAnyValue: (NSDictionary *)values; + +- (NSException *)validateKeysWithRootClassDescription: (EOClassDescription *)classDesc; + ++ (NSArray *)allQualifierOperators; + ++ (NSArray *)relationalQualifierOperators; + ++ (NSString *)stringForOperatorSelector: (SEL)selector; ++ (SEL)operatorSelectorForString: (NSString *)string; + +- (EOQualifier *)qualifierByApplyingBindings: (id)bindings; + +- (EOQualifier *)qualifierByApplyingBindingsAllVariablesRequired: (id)bindings; + +- (EOQualifier *)qualifierWithBindings: (NSDictionary *)bindings + requiresAllVariables: (BOOL)requiresAll; + +- (NSArray *)bindingKeys; +- (NSString *)keyPathForBindingKey: (NSString *)key; + +- (BOOL)evaluateWithObject: (id)object; + +@end + + +@interface EOQualifier (EOModelExtensions) + +- (EOQualifier *)qualifierMigratedFromEntity: (EOEntity *)entity + relationshipPath: (NSString *)relationshipPath; + +@end + + +@protocol EOQualifierEvaluation + +- (BOOL)evaluateWithObject: object; + +@end + + +@interface NSObject (EORelationalSelectors) + +- (BOOL)isEqualTo: (id)object; +- (BOOL)isLessThanOrEqualTo: (id)object; +- (BOOL)isLessThan: (id)object; +- (BOOL)isGreaterThanOrEqualTo: (id)object; +- (BOOL)isGreaterThan: (id)object; +- (BOOL)isNotEqualTo: (id)object; +- (BOOL)doesContain: (id)object; +- (BOOL)isLike: (NSString *)object; +- (BOOL)isCaseInsensitiveLike: (NSString *)object; + +@end + + +#define EOQualifierOperatorEqual @selector(isEqualTo:) +#define EOQualifierOperatorNotEqual @selector(isNotEqualTo:) +#define EOQualifierOperatorLessThan @selector(isLessThan:) +#define EOQualifierOperatorGreaterThan @selector(isGreaterThan:) +#define EOQualifierOperatorLessThanOrEqualTo @selector(isLessThanOrEqualTo:) +#define EOQualifierOperatorGreaterThanOrEqualTo @selector(isGreaterThanOrEqualTo:) +#define EOQualifierOperatorContains @selector(doesContain:) +#define EOQualifierOperatorLike @selector(isLike:) +#define EOQualifierOperatorCaseInsensitiveLike @selector(isCaseInsensitiveLike:) + + +@interface EOKeyValueQualifier:EOQualifier +{ + SEL _selector; + NSString *_key; + id _value; +} + ++ (EOKeyValueQualifier*)qualifierWithKey: (NSString *)key + operatorSelector: (SEL)selector + value: (id)value; + +- (id) initWithKey: (NSString *)key + operatorSelector: (SEL)selector + value: (id)value; +- (SEL)selector; +- (NSString *)key; +- (id)value; + +@end + +@interface EOKeyComparisonQualifier:EOQualifier +{ + SEL _selector; + NSString *_leftKey; + NSString *_rightKey; +} + ++ (EOQualifier*)qualifierWithLeftKey: (NSString *)leftKey + operatorSelector: (SEL)selector + rightKey: (id)rightKey; + +- initWithLeftKey: (NSString *)leftKey + operatorSelector: (SEL)selector + rightKey: (id)rightKey; +- (SEL)selector; +- (NSString *)leftKey; +- (NSString *)rightKey; + +@end + + +@interface EOAndQualifier : EOQualifier +{ + NSArray *_qualifiers; +} + ++ (EOQualifier *)qualifierWithQualifierArray: (NSArray *)array; ++ (EOQualifier *)qualifierWithQualifiers: (EOQualifier *)qualifiers, ...; + +- initWithQualifiers: (EOQualifier *)qualifiers, ...; +- initWithQualifierArray: (NSArray *)array; + +- (NSArray *)qualifiers; + +@end + + +@interface EOOrQualifier:EOQualifier +{ + NSArray *_qualifiers; +} + ++ (EOQualifier *)qualifierWithQualifierArray: (NSArray *)array; ++ (EOQualifier *)qualifierWithQualifiers: (EOQualifier *)qualifiers, ...; + +- initWithQualifiers: (EOQualifier *)qualifiers, ...; +- initWithQualifierArray: (NSArray *)array; + +- (NSArray *)qualifiers; + +@end + + +@interface EONotQualifier:EOQualifier +{ + EOQualifier *_qualifier; +} + ++ (EOQualifier *)qualifierWithQualifier: (EOQualifier *)qualifier; + +- initWithQualifier: (EOQualifier *)qualifier; + +- (EOQualifier *)qualifier; + +@end + +extern NSString *EOQualifierVariableSubstitutionException; + + +@interface EOQualifierVariable:NSObject +{ + NSString *_key; +} + ++ (EOQualifierVariable *)variableWithKey: (NSString *)key; +- (EOQualifierVariable *)initWithKey: (NSString *)key; +- (NSString *)key; + +- (id)valueByApplyingBindings: (id)bindings; + +- (id)requiredValueByApplyingBindings: (id)bindings; + +@end + + +@interface NSArray (EOQualifierExtras) +- (NSArray *)filteredArrayUsingQualifier: (EOQualifier *)qualifier; +@end + + +#endif diff --git a/EOControl/EOQualifier.m b/EOControl/EOQualifier.m new file mode 100644 index 0000000..be7d1d0 --- /dev/null +++ b/EOControl/EOQualifier.m @@ -0,0 +1,914 @@ +/** + EOQualifier.m EOQualifier + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#include +#include + +#import +#import +#import + +#import +#import +#import +#import + +#import +#import +#import + +@implementation NSNumber (EOQualifierExtras) +- (id)initWithString:(NSString *)string +{ + double dVal; + float fVal; + int iVal; + + dVal = [string doubleValue]; + fVal = [string floatValue]; + iVal = [string intValue]; + + if (dVal == iVal) + { + return [self initWithInt: iVal]; + } + else if (dVal == fVal) + { + return [self initWithFloat: fVal]; + } + else + { + return [self initWithDouble: dVal]; + } +} +@end + +@implementation EOQualifier + ++ (EOQualifier *)qualifierWithQualifierFormat: (NSString *)qualifierFormat, ... +{ + EOQualifier *qualifier = nil; + + if(qualifierFormat) + { + va_list ap; + + va_start(ap, qualifierFormat); + + qualifier = [EOQualifier qualifierWithQualifierFormat: qualifierFormat + varargList: ap]; + + va_end(ap); + } + + return qualifier; +} + ++ (EOQualifier *)qualifierWithQualifierFormat: (NSString *)format + arguments: (NSArray *)args +{ + [self notImplemented: _cmd]; + return nil; +} + +static NSString *getOperator(const char **cFormat, const char **s) +{ + NSString *operator; + + while (**s && isspace(**s)) + (*s)++; + + *cFormat = *s; + + if (isalnum(**s)) + { + while (**s && !isspace(**s) && **s != '%' && **s != '\'') + { + (*s)++; + } + + operator = [NSString stringWithCString: *cFormat length: *s - *cFormat]; + } + else + { + while (**s && !isalnum(**s) && !isspace(**s) && **s != '%' && **s != '\'') + { + NSDebugLog(@"avoid gcc 3.1.1 bug which optimizes to segfault"); + (*s)++; + } + + operator = [NSString stringWithCString: *cFormat length: *s - *cFormat]; + } + + *cFormat = *s; + + return operator; +} + +static id getKey(const char **cFormat, const char **s, BOOL *isKeyValue, + va_list *args) +{ + NSMutableString *key, *classString = nil; + char quoteChar; + BOOL quoted = NO; + + while (**s && isspace(**s)) + (*s)++; + + if (isKeyValue) + { + if (**s == '(') + { + (*s)++; *cFormat = *s; + + while (**s && **s != ')') + (*s)++; + + if (!*s); //TODO exception + + classString = [NSString stringWithCString: *cFormat + length: *s - *cFormat]; + + (*s)++; *cFormat = *s; + } + + if (!strncmp("nil", *s, 3)) + { + char value = *(*s+3); + + if (value == 0 || value == ' ') + { + *cFormat = *s = *s+3; + return nil; + } + } + } + + quoteChar = **s; + if (quoteChar && (quoteChar == '"' || quoteChar == '\'')) + { + quoted = YES; + (*s)++; + } + + *cFormat = *s; + + if (quoted) + { + while (**s && **s != quoteChar) + (*s)++; + + key = [NSString stringWithCString: *cFormat length: *s - *cFormat]; + (*s)++; // skip closing quote + } + else + { + key = [NSMutableString stringWithCapacity:8]; + + while (**s && (isalnum(**s) || **s == '@' || **s == '#' || **s == '_' + || **s == '$' || **s == '%' || **s == '.')) + { + if (**s == '%') + { + const char *argString; + NSString *argObj; + //float argFloat; + double argFloat; // `float' is promoted to `double' when passed through `...' (so you should pass `double' not `float' to `va_arg') + + int argInt; + + if (isKeyValue) + { + *isKeyValue = YES; + } + + switch (*(*s+1)) + { + case '@': + argObj = va_arg(*args, id); + + if (isKeyValue && *isKeyValue == YES && quoted == NO + && classString == nil) + { + *cFormat = *s = *s+2; + return argObj; + } + else + { + if (*cFormat != *s) + [key appendString: [NSString stringWithCString: *cFormat + length: *s - *cFormat]]; + + [key appendString: [argObj description]]; + *cFormat = *s+2; + (*s)++; + } + break; + + case 's': + argString = va_arg(*args, const char *); + + if (isKeyValue && *isKeyValue == YES && quoted == NO + && classString == nil) + { + *cFormat = *s = *s + 2; + return [NSString stringWithCString: argString]; + } + else + { + if (*cFormat != *s) + [key appendString: [NSString stringWithCString: *cFormat + length: *s - *cFormat]]; + + [key appendString: [NSString + stringWithCString: argString]]; + *cFormat = *s + 2; + (*s)++; + } + break; + + case 'd': + argInt = va_arg(*args, int); + + if (isKeyValue && *isKeyValue == YES && quoted == NO + && classString == nil) + { + *cFormat = *s = *s + 2; + return [NSNumber numberWithInt: argInt]; + } + else + { + if(*cFormat != *s) + [key appendString: [NSString stringWithCString: *cFormat + length: *s - *cFormat]]; + + [key appendString: [NSString stringWithFormat: @"%d", + argInt]]; + *cFormat = *s + 2; + (*s)++; + } + break; + + case 'f': + argFloat = va_arg(*args, double);// `float' is promoted to `double' when passed through `...' (so you should pass `double' not `float' to `va_arg') + + if (isKeyValue && *isKeyValue == YES && quoted == NO + && classString == nil) + { + *cFormat = *s = *s + 2; + return [NSNumber numberWithFloat: argFloat]; + } + else + { + if (*cFormat != *s) + [key appendString: [NSString stringWithCString: *cFormat + length: *s - *cFormat]]; + + [key appendString: [NSString stringWithFormat: @"%f", + argFloat]]; + *cFormat = *s + 2; + (*s)++; + } + break; + + case '%': + *cFormat = *s + 2; + (*s)++; + [key appendString: [NSString stringWithCString: *cFormat + length: *s - *cFormat]]; + break; + + default: + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@: unrecognized character (%c) in the conversion specification", @"qualifierParser", @"EOQualifier", *(*s + 1)]; + break; + } + } + + (*s)++; + } + + if (*cFormat != *s) + [key appendString: [NSString stringWithCString: *cFormat + length: *s - *cFormat]]; + } + + if (isKeyValue) + { + *isKeyValue = quoted; + + if (classString) + { + key = [[[NSClassFromString(classString) alloc] initWithString: key] autorelease]; + } + } + + *cFormat = *s; + + return key; +} + +static BOOL isNotQualifier(const char **cFormat, const char **s) +{ + while (**s && isspace(**s)) + (*s)++; + + *cFormat = *s; + + if (!strncasecmp(*s, "not", 3)) + { + switch ((*s)[3]) + { + case ' ': + case '(': + case 0: + *cFormat = *s = *s+3; + return YES; + } + } + + return NO; +} + +static Class whichQualifier(const char **cFormat, const char **s) +{ + while (**s && isspace(**s)) + (*s)++; + + *cFormat = *s; + + if (!strncasecmp(*s, "and", 3)) + { + switch ((*s)[3]) + { + case ' ': + case '(': + case 0: + *cFormat = *s = *s+3; + return [EOAndQualifier class]; + } + } + else if (!strncasecmp(*s, "or", 2)) + { + switch ((*s)[2]) + { + case ' ': + case '(': + case 0: + *cFormat = *s = *s+2; + return [EOOrQualifier class]; + } + } + + return Nil; +} + ++ (EOQualifier *)qualifierWithQualifierFormat: (NSString *)format + varargList: (va_list)args +{ + const char *s; + const char *cFormat; + NSMutableArray *bracketStack = nil; + NSMutableArray *qualifierArray = nil; + NSMutableArray *parentQualifiers = nil; + EOQualifier *qualifier = nil; + NSString *leftKey; + NSString *rightKey; + NSString *operator; + SEL operatorSelector = NULL; + BOOL isKeyValue = NO; + BOOL notQual; + Class lastQualifierClass = Nil; + Class qualifierClass = Nil; + + bracketStack = [NSMutableArray array]; + parentQualifiers = [NSMutableArray array]; + + cFormat = s = [format cString]; + + while (*s) + { + while (*s && isspace(*s)) + (s)++; + + while (*s == '(' ) + { + NSMutableDictionary *state; + + state = [NSMutableDictionary dictionaryWithCapacity:4]; + if (lastQualifierClass != NULL) + { + [state setObject: lastQualifierClass forKey: @"lastQualifierClass"]; + lastQualifierClass = NULL; + } + if (qualifierArray != nil) + { + [state setObject: qualifierArray forKey: @"qualifierArray"]; + qualifierArray = nil; + } + if (qualifierClass != nil) + { + [state setObject: qualifierClass forKey: @"qualifierClass"]; + qualifierClass = nil; + } + [state setObject: parentQualifiers forKey: @"parentQualifiers"]; + parentQualifiers = [NSMutableArray new]; + + [bracketStack addObject:state]; + + (s)++; // skip '(' + while (*s && isspace(*s)) + (s)++; + } + + notQual = isNotQualifier(&cFormat, &s); + leftKey = getKey(&cFormat, &s, NULL, &args); + operator = getOperator(&cFormat, &s); + rightKey = getKey(&cFormat, &s, &isKeyValue, &args); + + operatorSelector = [EOQualifier operatorSelectorForString: operator]; + + EOFLOGObjectLevelArgs(@"EOQualifier", + @"leftKey=%@ operatorSelector=%s rightKey=%@ class=%@", + leftKey, + GSObjCSelectorName(operatorSelector), + rightKey, + isKeyValue?@"EOKeyValueQualifier":@"EOKeyComparisonQualifier"); + + if (isKeyValue) + qualifier = [EOKeyValueQualifier qualifierWithKey: leftKey + operatorSelector: operatorSelector + value: rightKey]; + else + qualifier = [EOKeyComparisonQualifier + qualifierWithLeftKey: leftKey + operatorSelector: operatorSelector + rightKey: rightKey]; + + EOFLOGObjectLevelArgs(@"EOQualifier", + @"qualifier=%@", + qualifier); + + if (notQual) + qualifier = [EONotQualifier qualifierWithQualifier: qualifier]; + + EOFLOGObjectLevelArgs(@"EOQualifier", + @"qualifier=%@", + qualifier); + + while (*s && isspace(*s)) + (s)++; + + while (*s == ')' ) + { + NSMutableDictionary *state; + + /* clean up inner qualifier */ + if (qualifierArray != nil) + { + [qualifierArray addObject:qualifier]; + qualifier = AUTORELEASE([[qualifierClass alloc] initWithQualifierArray:qualifierArray]); + qualifierArray = nil; + } + + while ([parentQualifiers count] != 0) + { + id parent; + NSArray *quals; + + parent = [parentQualifiers lastObject]; + quals = [[parent qualifiers] arrayByAddingObject: qualifier]; + qualifier = AUTORELEASE([[[parent class] alloc] + initWithQualifierArray: quals]); + [parentQualifiers removeLastObject]; + } + + DESTROY(parentQualifiers); + + /* pop bracketStack */ + state = [bracketStack lastObject]; + qualifierArray = [state objectForKey:@"qualifierArray"]; + lastQualifierClass = [state objectForKey:@"lastQualifierClass"]; + qualifierClass = [state objectForKey:@"qualifierClass"]; + parentQualifiers = [state objectForKey:@"parentQualifiers"]; + + [bracketStack removeLastObject]; + + (s)++; // skip ')' + while (*s && isspace(*s)) + (s)++; + } + + qualifierClass = whichQualifier(&cFormat, &s); + EOFLOGObjectLevelArgs(@"EOQualifier", @"qualifierClass=%@", + qualifierClass); + + if ([bracketStack count]==0) + { + if (qualifierClass == Nil) + break; + } + if (lastQualifierClass == Nil) + { + qualifierArray = [NSMutableArray arrayWithObject: qualifier]; + } + else if (lastQualifierClass == qualifierClass) + { + [qualifierArray addObject: qualifier]; + } + else /* lastQualifierClass set and != qualifierClass */ + { + [parentQualifiers addObject: + AUTORELEASE([[lastQualifierClass alloc] + initWithQualifierArray: qualifierArray])]; + + qualifierArray = [NSMutableArray arrayWithObject: qualifier]; + } + + lastQualifierClass = qualifierClass; + } + + /* this is reached after the break */ + if (lastQualifierClass != Nil) + { + if (qualifier == nil) + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: missing qualifier", + NSStringFromSelector(_cmd), + NSStringFromClass([self class]), self]; + + [qualifierArray addObject: qualifier]; + + qualifier = AUTORELEASE([[lastQualifierClass alloc] + initWithQualifierArray: qualifierArray]); + + EOFLOGObjectLevelArgs(@"EOQualifier", + @"qualifier=%@", + qualifier); + } + + while ([parentQualifiers count] != 0) + { + id parent; + NSArray *quals; + + parent = [parentQualifiers lastObject]; + quals = [[parent qualifiers] arrayByAddingObject: qualifier]; + qualifier = AUTORELEASE([[[parent class] alloc] + initWithQualifierArray: quals]); + [parentQualifiers removeLastObject]; + } + + return qualifier; +} + ++ (EOQualifier *)qualifierToMatchAllValues: (NSDictionary *)values +{ + NSEnumerator *keyEnumerator; + NSString *key; + NSMutableArray *array; + + array = [NSMutableArray arrayWithCapacity: [values count]]; + + keyEnumerator = [values keyEnumerator]; + while ((key = [keyEnumerator nextObject])) + [array addObject: [EOKeyValueQualifier + qualifierWithKey: key + operatorSelector: EOQualifierOperatorEqual + value: [values objectForKey: key]]]; + + if ([array count] == 1) + return [array objectAtIndex: 0]; + + return [EOAndQualifier qualifierWithQualifierArray: array]; +} + ++ (EOQualifier *)qualifierToMatchAnyValue:(NSDictionary *)values +{ + NSEnumerator *keyEnumerator; + NSString *key; + NSMutableArray *array; + + array = [NSMutableArray arrayWithCapacity: [values count]]; + + keyEnumerator = [values keyEnumerator]; + while ((key = [keyEnumerator nextObject])) + [array addObject:[EOKeyValueQualifier + qualifierWithKey: key + operatorSelector: EOQualifierOperatorEqual + value: [values objectForKey: key]]]; + + if ([array count] == 1) + return [array objectAtIndex: 0]; + + return [EOOrQualifier qualifierWithQualifierArray: array]; +} + +- (NSException *)validateKeysWithRootClassDescription: (EOClassDescription *)classDesc +{ + return [self notImplemented: _cmd]; //TODO +} + ++ (NSArray *)allQualifierOperators +{ // rivedere + return [NSArray arrayWithObjects:@"=", @"!=", @"<=", @"<", @">=", @">", @"contains", @"like", @"caseInsensitiveLike"]; +} + ++ (NSArray *)relationalQualifierOperators +{ // rivedere + return [NSArray arrayWithObjects:@"=", @"!=", @"<=", @"<", @">=", @">"]; +} + ++ (NSString *)stringForOperatorSelector: (SEL)selector +{ + if (sel_eq(selector, EOQualifierOperatorEqual)) + return @"="; + else if (sel_eq(selector, EOQualifierOperatorNotEqual)) + return @"!="; + else if (sel_eq(selector, EOQualifierOperatorLessThan)) + return @"<"; + else if (sel_eq(selector, EOQualifierOperatorGreaterThan)) + return @">"; + else if (sel_eq(selector, EOQualifierOperatorLessThanOrEqualTo)) + return @"<="; + else if (sel_eq(selector, EOQualifierOperatorGreaterThanOrEqualTo)) + return @">="; + else if (sel_eq(selector, EOQualifierOperatorContains)) + return @"contains"; + else if (sel_eq(selector, EOQualifierOperatorLike)) + return @"like"; + else if (sel_eq(selector, EOQualifierOperatorCaseInsensitiveLike)) + return @"caseInsensitiveLike"; + + return nil; +} + ++ (SEL)operatorSelectorForString: (NSString *)string +{ + if ([string isEqualToString: @"="]) + return EOQualifierOperatorEqual; + else if ([string isEqualToString: @"=="]) + return EOQualifierOperatorEqual; + else if ([string isEqualToString: @"<="]) + return EOQualifierOperatorLessThanOrEqualTo; + else if ([string isEqualToString: @"<"]) + return EOQualifierOperatorLessThan; + else if ([string isEqualToString: @">="]) + return EOQualifierOperatorGreaterThanOrEqualTo; + else if ([string isEqualToString: @">"]) + return EOQualifierOperatorGreaterThan; + else if ([string isEqualToString: @"<>"]) + return EOQualifierOperatorNotEqual; + else if ([string isEqualToString: @"!="]) + return EOQualifierOperatorNotEqual; + else if ([string isEqualToString: @"contains"]) + return EOQualifierOperatorContains; + else if ([string isEqualToString: @"like"]) + return EOQualifierOperatorLike; + else if ([string isEqualToString: @"caseInsensitiveLike"]) + return EOQualifierOperatorCaseInsensitiveLike; + else + { + NSWarnMLog(@"No operator selector for string '%@'.", string); + return (SEL)nil; // ???? + } +} + +- (id)copyWithZone: (NSZone *)zone +{ + return NSCopyObject(self, 0, zone); +} + +- (EOQualifier *)qualifierByApplyingBindings: (id)bindings +{ + return [self qualifierWithBindings: bindings + requiresAllVariables: NO]; +} + +- (EOQualifier *)qualifierByApplyingBindingsAllVariablesRequired: (id)bindings +{ + return [self qualifierWithBindings: bindings + requiresAllVariables: YES]; +} + +- (EOQualifier *)qualifierWithBindings: (NSDictionary *)bindings + requiresAllVariables: (BOOL)requiresAll +{ + // TODO + [self notImplemented: _cmd]; + return nil; +} + +- (NSArray *)bindingKeys +{ + // TODO + [self notImplemented: _cmd]; + return nil; +} + +//NO +- (BOOL)evaluateWithObject: (id)object +{ + [self notImplemented: _cmd]; + return NO; +} + +- (NSString *)keyPathForBindingKey: (NSString *)key +{ + // TODO + [self notImplemented: _cmd]; + return nil; +} + +- (void) _addBindingsToDictionary: (id)param0 +{ + [self notImplemented: _cmd]; //TODO +} + +- (EOQualifier *)qualifierMigratedFromEntity: (EOEntity *)entity + relationshipPath: (NSString *)relationshipPath +{ + return [self notImplemented: _cmd]; //TODO +} + +- (id) _qualifierMigratedToSubEntity: (id)param0 + fromParentEntity: (id)param1 +{ + return [self notImplemented: _cmd]; //TODO +} + +- (BOOL) usesDistinct +{ + [self notImplemented: _cmd]; //TODO + return NO; +} + +@end + + +@implementation EOQualifierVariable + ++ (EOQualifierVariable *)variableWithKey: (NSString *)key +{ + return [EOQualifierVariable variableWithKey: key]; +} + +- (EOQualifierVariable *)initWithKey: (NSString *)key +{ + if ((self = [super init])) + { + ASSIGN(_key, key); + } + + return self; +} + +- (NSString *)key +{ + return _key; +} + +- (void)encodeWithCoder: (NSCoder *)coder +{ + [coder encodeObject: _key]; +} + +- (id)initWithCoder: (NSCoder *)coder +{ + if ((self = [super init])) + { + _key = [[coder decodeObject] retain]; + } + + return self; +} + +- (id)valueByApplyingBindings: (id)bindings +{ + return [self notImplemented: _cmd]; //TODO +} + +- (id)requiredValueByApplyingBindings: (id)bindings +{ + return [self notImplemented: _cmd]; //TODO +} + +- (id) initWithKeyValueUnarchiver: (EOKeyValueUnarchiver *)unarchiver +{ + return [self notImplemented: _cmd]; //TODO +} + +- (void)encodeWithKeyValueArchiver: (EOKeyValueArchiver *)archiver +{ + [self notImplemented: _cmd]; //TODO +} + +@end + + +@implementation NSObject (EORelationalSelectors) + +- (BOOL)isEqualTo: (id)object +{ + return [self isEqual: object]; +} + +- (BOOL)isLessThanOrEqualTo: (id)object +{ + NSComparisonResult res = [self compare: object]; + + return (res == NSOrderedAscending || res == NSOrderedSame ? YES : NO); +} + +- (BOOL)isLessThan: (id)object +{ + return ([self compare:object] == NSOrderedAscending ? YES : NO); +} + +- (BOOL)isGreaterThanOrEqualTo: (id)object +{ + NSComparisonResult res = [self compare:object]; + + return (res == NSOrderedDescending || res == NSOrderedSame ? YES : NO); +} + +- (BOOL)isGreaterThan: (id)object +{ + return ([self compare: object] == NSOrderedDescending ? YES : NO); +} + +- (BOOL)isNotEqualTo: (id)object +{ + return ([self isEqual: object] ? NO : YES); +} + +- (BOOL)doesContain: (id)object +{ + if ([self isKindOfClass: [NSArray class]] + || [self isKindOfClass: [NSMutableArray class]]) + return [(NSArray *)self containsObject: object]; + + return NO; +} + +- (BOOL)isLike: (NSString *)object +{ + return NO; +} + +- (BOOL)isCaseInsensitiveLike: (NSString *)object +{ + return NO; +} + +@end + + +@implementation NSString (EORelationalSelectors) + +- (BOOL)isLike: (NSString *)object +{ + NSEmitTODO(); //TODO + return [self isEqual: object] == NSOrderedSame; +} + +- (BOOL)isCaseInsensitiveLike: (NSString *)object +{ + NSEmitTODO(); //TODO + return [[self uppercaseString] + isEqual: [object uppercaseString]] == NSOrderedSame; +} + +@end diff --git a/EOControl/EOSortOrdering.h b/EOControl/EOSortOrdering.h new file mode 100644 index 0000000..a39a207 --- /dev/null +++ b/EOControl/EOSortOrdering.h @@ -0,0 +1,91 @@ +/* + EOSortOrdering.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOSortOrdering_h__ +#define __EOSortOrdering_h__ + + +#import + +#import + + +@interface EOSortOrdering : NSObject +{ + SEL _selector; + NSString *_key; +} + ++ (EOSortOrdering *)sortOrderingWithKey: (NSString *)key + selector: (SEL)selector; + +- initWithKey: (NSString *)key selector: (SEL)selector; +- (NSString *)key; +- (SEL)selector; + +@end + + +@interface NSArray (EOKeyBasedSorting) + +- (NSArray *)sortedArrayUsingKeyOrderArray: (NSArray *)orderArray; + +@end + + +@interface NSMutableArray (EOKeyBasedSorting) + +- (void)sortUsingKeyOrderArray: (NSArray *)orderArray; + +@end + + +@interface NSObject (EOSortOrderingComparison) + +- (NSComparisonResult)compareAscending: (id)other; +- (NSComparisonResult)compareDescending: (id)other; +- (NSComparisonResult)compareCaseInsensitiveAscending: (id)other; +- (NSComparisonResult)compareCaseInsensitiveDescending: (id)other; + +@end + + +@interface EONull (EOSortOrderingComparison) + +- (NSComparisonResult)compareAscending: (id)other; +- (NSComparisonResult)compareDescending: (id)other; +- (NSComparisonResult)compareCaseInsensitiveAscending: (id)other; +- (NSComparisonResult)compareCaseInsensitiveDescending: (id)other; + +@end + +#define EOCompareAscending @selector(compareAscending:) +#define EOCompareDescending @selector(compareDescending:) +#define EOCompareCaseInsensitiveAscending @selector(compareCaseInsensitiveAscending:) +#define EOCompareCaseInsensitiveDescending @selector(compareCaseInsensitiveDescending:) + + +#endif diff --git a/EOControl/EOSortOrdering.m b/EOControl/EOSortOrdering.m new file mode 100644 index 0000000..3491e0e --- /dev/null +++ b/EOControl/EOSortOrdering.m @@ -0,0 +1,388 @@ +/** + EOSortOrdering.m EOSortOrdering + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: February 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import +#import +#import + + +@implementation EOSortOrdering + ++ (EOSortOrdering *)sortOrderingWithKey: (NSString *)key + selector: (SEL)selector +{ + return [[[self alloc] initWithKey: key + selector: selector] + autorelease]; +} + +- (void)encodeWithCoder: (NSCoder *)coder +{ + [coder encodeValueOfObjCType: @encode(SEL) at: _selector]; + [coder encodeObject: _key]; +} + +- (id)initWithCoder: (NSCoder *)coder +{ + self = [super init]; + + [coder decodeValueOfObjCType: @encode(SEL) at: &_selector]; + _key = [[coder decodeObject] retain]; + + return self; +} + +- initWithKey: (NSString *)key selector: (SEL)selector +{ + self = [super init]; + + ASSIGN(_key, key); + _selector = selector; + + return self; +} + +- (NSString *)key +{ + return _key; +} + +- (SEL)selector +{ + return _selector; +} + +- (id) initWithKeyValueUnarchiver: (EOKeyValueUnarchiver*)unarchiver +{ + EOFLOGObjectFnStartOrCond(@"EOSortOrdering"); + + if ((self = [super init])) + { + NSString *selectorName; + + ASSIGN(_key, [unarchiver decodeObjectForKey: @"key"]); + selectorName = [unarchiver decodeObjectForKey: @"selectorName"]; + + if (selectorName) + _selector = NSSelectorFromString(selectorName); + } + + EOFLOGObjectFnStopOrCond(@"EOSortOrdering"); + + return self; +} + +- (void) encodeWithKeyValueArchiver: (EOKeyValueUnarchiver*)archiver +{ + [self notImplemented: _cmd]; +} + +@end + + +@implementation NSArray (EOKeyBasedSorting) + +- (NSArray *)sortedArrayUsingKeyOrderArray: (NSArray *)orderArray +{ + // A fast-coding way + //TODO a better way (see sortUsingKeyOrderArray:) + + if ([self count] <= 1) + return self; + else + { + NSMutableArray *sortedArray = [[self mutableCopy] autorelease]; + + [sortedArray sortUsingKeyOrderArray: orderArray]; + + // make array immutable but don't copy as mutable arrays copy deep + return [NSArray arrayWithArray: sortedArray]; + } +} + +@end + + +@implementation NSMutableArray (EOKeyBasedSorting) + +- (void)_sortUsingKeyOrder: (EOSortOrdering *)order + fromIndex: (int)index + count: (int)count +{ + /* Shell sort algorithm taken from SortingInAction - a NeXT example */ +#define STRIDE_FACTOR 3 // good value for stride factor is not well-understood + // 3 is a fairly good choice (Sedgewick) + unsigned c, d, stride; + BOOL found; +#ifdef GSWARN + BOOL badComparison = NO; +#endif + NSString *orderKey; + SEL orderSel; + int type; + EONull *null = (EONull *)[EONull null]; + + orderKey = [order key]; + orderSel = [order selector]; + + type = 1; + + if (sel_eq(orderSel, EOCompareAscending)) + type = 1; + else if (sel_eq(orderSel, EOCompareDescending)) + type = 2; + else if (sel_eq(orderSel, EOCompareCaseInsensitiveAscending)) + type = 3; + else if (sel_eq(orderSel, EOCompareCaseInsensitiveDescending)) + type = 4; + + stride = 1; + while (stride <= count) + { + stride = stride * STRIDE_FACTOR + 1; + } + + while (stride > (STRIDE_FACTOR - 1)) + { + // loop to sort for each value of stride + stride = stride / STRIDE_FACTOR; + + for (c = stride; c < count; c++) + { + found = NO; + if (stride > c) + { + break; + } + + d = c - stride + index; + while (!found) /* move to left until correct place */ + { + id a = [self objectAtIndex: d + stride]; + id b = [self objectAtIndex: d]; + id aValue = [a valueForKey: orderKey]; + id bValue = [b valueForKey: orderKey]; + NSComparisonResult r; + + if (aValue == nil) + aValue = null; + else if (bValue == nil) + { + bValue = aValue; + aValue = null; + } + + switch (type) + { + default: + case 1: + r = [aValue compareAscending: bValue]; + break; + case 2: + r = [aValue compareDescending: bValue]; + break; + case 3: + r = [aValue compareCaseInsensitiveAscending: bValue]; + break; + case 4: + r = [aValue compareCaseInsensitiveDescending: bValue]; + break; + } + + if (aValue == null && bValue != nil && bValue != null) + r = ~r+1; + + if (r < 0) + { +#ifdef GSWARN + if (r != NSOrderedAscending) + { + badComparison = YES; + } +#endif + IF_NO_GC(RETAIN(a)); + [self replaceObjectAtIndex: d + stride withObject: b]; + [self replaceObjectAtIndex: d withObject: a]; + RELEASE(a); + if ((stride + index) > d) + { + break; + } + d -= stride; // jump by stride factor + } + else + { +#ifdef GSWARN + if (r != NSOrderedDescending && r != NSOrderedSame) + { + badComparison = YES; + } +#endif + found = YES; + } + } + } + } +#ifdef GSWARN + if (badComparison == YES) + { + NSWarnMLog(@"Detected bad return value from comparison", 0); + } +#endif +} + +- (void)sortUsingKeyOrderArray: (NSArray *)orderArray +{ + int count = [self count]; + + if (count > 1) + { + EOSortOrdering *order; + NSEnumerator *orderEnum; + //NSString *key; + + orderEnum = [orderArray objectEnumerator]; + if ((order = [orderEnum nextObject])) + { + //id a, b; + + [self _sortUsingKeyOrder: order + fromIndex: 0 + count: [self count]]; +#if 0 + key = [order key]; + + a = [[self objectAtIndex: i] valueForKey: key]; + + for (i = index; i < (count - 1); i++) + { + b = [[self objectAtIndex: i + 1] valueForKey: key]; + + if ([a compare: b] == NSOrderedSame) + { + start = i; + } + + a = b; + } +#endif + } + } +} + +@end + + +@implementation NSObject (EOSortOrderingComparison) + +- (NSComparisonResult)compareAscending: (id)other +{ + return [self compare: other]; +} + +- (NSComparisonResult)compareDescending: (id)other +{ + NSComparisonResult result = [self compare: other]; + + return (~result + 1); +} + +- (NSComparisonResult)compareCaseInsensitiveAscending: (id)other +{ + return [self compare: other]; +} + +- (NSComparisonResult)compareCaseInsensitiveDescending: (id)other +{ + NSComparisonResult result = [self compare: other]; + + return (~result + 1); +} + +@end + + +@implementation EONull (EOSortOrderingComparison) + +- (NSComparisonResult)compareAscending: (id)other +{ + if (other == nil || self == other) + return NSOrderedSame; + + return NSOrderedAscending; +} + +- (NSComparisonResult)compareDescending: (id)other +{ + if (other == nil || self == other) + return NSOrderedSame; + + return NSOrderedDescending; +} + +- (NSComparisonResult)compareCaseInsensitiveAscending: (id)other +{ + if (other == nil || self == other) + return NSOrderedSame; + + return NSOrderedAscending; +} + +- (NSComparisonResult)compareCaseInsensitiveDescending: (id)other +{ + if (other == nil || self == other) + return NSOrderedSame; + + return NSOrderedDescending; +} + +@end + + +@implementation NSString (EOSortOrderingComparison) + +- (NSComparisonResult)compareCaseInsensitiveAscending: (id)other +{ + return [self caseInsensitiveCompare: other]; +} + +- (NSComparisonResult)compareCaseInsensitiveDescending: (id)other +{ + NSComparisonResult result = [self caseInsensitiveCompare: other]; + + return (~result + 1); +} + +@end diff --git a/EOControl/EOUndoManager.h b/EOControl/EOUndoManager.h new file mode 100644 index 0000000..b04a699 --- /dev/null +++ b/EOControl/EOUndoManager.h @@ -0,0 +1,38 @@ +/* + EOUndoManager.h + + Copyright (C) 2000 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: October 2000 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#import + +@interface EOUndoManager : NSUndoManager + +- (void) forgetAllWithTarget: (id)param0; +- (void) forgetAll; +- (void) registerUndoWithTarget: (id)param0 + selector: (SEL)param1 + arg: (id)param2; +- (void) reenableUndoRegistration; + +@end diff --git a/EOControl/EOUndoManager.m b/EOControl/EOUndoManager.m new file mode 100644 index 0000000..3264ec2 --- /dev/null +++ b/EOControl/EOUndoManager.m @@ -0,0 +1,87 @@ +/** + EOUndoManager.m EOUndoManager + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: October 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#import + +#import +#import + +@implementation EOUndoManager + +- (void) forgetAllWithTarget: (id)param0 +{ + EOFLOGObjectFnStart(); + + [self notImplemented: _cmd]; //TODO + + EOFLOGObjectFnStop(); +} + +- (void) forgetAll +{ + EOFLOGObjectFnStart(); + + [self notImplemented: _cmd]; //TODO + + EOFLOGObjectFnStop(); +} + +- (void) registerUndoWithTarget: (id)target + selector: (SEL)sel + arg: (id)arg +{ + EOFLOGObjectFnStart(); + + [self notImplemented: _cmd]; //TODO +// [self _registerUndoObject:_NSUndoLightInvocation target/selector/object]; +/*_registerUndoObject: + call _prepareEventGrouping + beginUndoGrouping + _prepareEventGrouping + postNotificationName:NSUndoManagerDidOpenUndoGroupNotification object:self +*/ + EOFLOGObjectFnStop(); +} + +- (void) reenableUndoRegistration +{ + EOFLOGObjectFnStart(); + + [self notImplemented: _cmd]; //TODO + + EOFLOGObjectFnStop(); +} + +@end diff --git a/EOControl/GNUmakefile b/EOControl/GNUmakefile new file mode 100644 index 0000000..0221e7b --- /dev/null +++ b/EOControl/GNUmakefile @@ -0,0 +1,129 @@ +# +# eoaccess makefile for GNUstep Database Library. +# +# Copyright (C) 1997 Free Software Foundation, Inc. +# +# Written by: Scott Christley +# +# This file is part of the GNUstep Database Library. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +# Install into the system root by default +GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_SYSTEM_ROOT) + +GNUSTEP_MAKEFILES = $(GNUSTEP_SYSTEM_ROOT)/Makefiles + +include $(GNUSTEP_MAKEFILES)/common.make + +include ../Version + +# The library to be compiled +LIBRARY_NAME=libgnustep-db2control + +libgnustep-db2control_LIBRARIES_DEPEND_UPON = -lgnustep-base -lFoundationExt + +# The C source files to be compiled +libgnustep-db2control_C_FILES = + +# The Objective-C source files to be compiled +libgnustep-db2control_OBJC_FILES = \ +EOSortOrdering.m \ +EOFetchSpecification.m \ +EOGenericRecord.m \ +EOClassDescription.m \ +EOKeyValueCodingBase.m \ +EOKeyValueCoding.m \ +EOKeyValueArchiver.m \ +EOQualifier.m \ +EOKeyValueQualifier.m \ +EOKeyComparisonQualifier.m \ +EOAndQualifier.m \ +EOOrQualifier.m \ +EONotQualifier.m \ +EONull.m \ +EOObjectStore.m \ +EOObjectStoreCoordinator.m \ +EOFaultHandler.m \ +EOFault.m \ +EOGlobalID.m \ +EOKeyGlobalID.m \ +EOObserver.m \ +EOEditingContext.m \ +EODataSource.m \ +EODetailDataSource.m \ +EOUndoManager.m \ +EOMutableKnownKeyDictionary.m \ +EONSAddOns.m \ +EOCheapArray.m \ +EODebug.m + +libgnustep-db2control_HEADER_FILES_DIR = . +libgnustep-db2control_HEADER_FILES_INSTALL_DIR = /EOControl + +libgnustep-db2control_HEADER_FILES = \ +EOSortOrdering.h \ +EOFetchSpecification.h \ +EOGenericRecord.h \ +EOClassDescription.h \ +EOKeyValueCodingBase.h \ +EOKeyValueCoding.h \ +EOKeyValueArchiver.h \ +EOQualifier.h \ +EONull.h \ +EOObjectStore.h \ +EOObjectStoreCoordinator.h \ +EOFault.h \ +EOGlobalID.h \ +EOKeyGlobalID.h \ +EOObserver.h \ +EOEditingContext.h \ +EODataSource.h \ +EODetailDataSource.h \ +EOUndoManager.h \ +EODebug.h \ +EOControl.h + +gdl2control_AUTOGSDOC_HEADERS = $(libgnustep-db2control_HEADER_FILES) +gdl2control_AUTOGSDOC_SOURCE = $(libgnustep-db2control_OBJC_FILES) +DOCUMENT_NAME = gdl2control +gdl2control_HEADER_FILES_DIR = $(HEADER_DIR) +gdl2control_AGSDOC_FILES = gdl2control.gsdoc $(gdl2control_AUTOGSDOC_HEADERS) +#$(gdl2control_AUTOGSDOC_SOURCE) +gdl2control_AGSDOC_FLAGS = \ + -Declared Foundation \ + -Standards YES \ + -SystemProjects System \ + -Project gdl2control \ + -WordMap '{\ + FOUNDATION_EXPORT=extern;FOUNDATION_STATIC_INLINE="";\ + GS_GEOM_SCOPE=extern;GS_GEOM_ATTR="";\ + GS_EXPORT=extern;GS_DECLARE="";\ + GS_RANGE_SCOPE=extern;GS_RANGE_ATTR="";\ + GS_ZONE_SCOPE=extern;GS_ZONE_ATTR="";\ + }' -Up gdl2control + +-include Makefile.preamble + +-include GNUmakefile.local + +include $(GNUSTEP_MAKEFILES)/library.make +# Only build the doc if doc=yes was passed on the command line +ifeq ($(doc),yes) +include $(GNUSTEP_MAKEFILES)/documentation.make +endif + +-include Makefile.postamble diff --git a/EOControl/Makefile.postamble b/EOControl/Makefile.postamble new file mode 100644 index 0000000..aad11d6 --- /dev/null +++ b/EOControl/Makefile.postamble @@ -0,0 +1,74 @@ +# +# Makefile.postamble +# +# Copyright (C) 1997 Free Software Foundation, Inc. +# +# Written by: Scott Christley +# +# This file is part of the GNUstep Database Library. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +# +# Makefile.postamble +# +# Project specific makefile rules +# +# Uncomment the targets you want. +# The double colons (::) are important, do not make them single colons +# otherwise the normal makefile rules will not be performed. +# + +# Things to do before compiling +before-all:: $(GNUSTEP_OBJ_DIR)/exceptions + +# Things to do after compiling +# after-all:: + +# Things to do before installing +# before-install:: + +# Things to do after installing +# after-install:: + +# Things to do before uninstalling +# before-uninstall:: + +# Things to do after uninstalling +# after-uninstall:: + +# Things to do before cleaning +# before-clean:: + +# Things to do after cleaning +# after-clean:: + +# Things to do before distcleaning +# before-distclean:: + +# Things to do after distcleaning +# after-distclean:: + +# Things to do before checking +# before-check:: + +# Things to do after checking +# after-check: + +$(GNUSTEP_OBJ_DIR)/exceptions: + $(MKDIRS) $@ + +$(GNUSTEP_OBJ_DIR)/EOModel$(OEXT): EOKeyValueCoding.m EOCustomValues.m diff --git a/EOControl/Makefile.preamble b/EOControl/Makefile.preamble new file mode 100644 index 0000000..f9b51b0 --- /dev/null +++ b/EOControl/Makefile.preamble @@ -0,0 +1,73 @@ +# +# Makefile.preamble +# +# Copyright (C) 1997 Free Software Foundation, Inc. +# +# Written by: Scott Christley +# +# This file is part of the GNUstep Database Library. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +# +# Makefile.preamble +# +# Project specific makefile variables, and additional +# +# Do not put any Makefile rules in this file, instead they should +# be put into Makefile.postamble. +# + +# +# Flags dealing with compiling and linking +# + +# Additional flags to pass to the preprocessor +ADDITIONAL_CPPFLAGS = $(FND_DEFINE) $(RUNTIME_DEFINE) -g + +# Additional flags to pass to the Objective-C compiler +ADDITIONAL_OBJCFLAGS = + +# Additional flags to pass to the C compiler +ADDITIONAL_CFLAGS = + +# Additional include directories the compiler should search +ADDITIONAL_INCLUDE_DIRS = -I.. + +# Additional LDFLAGS to pass to the linker +ADDITIONAL_LDFLAGS = + +# Additional library directories the linker should search +ADDITIONAL_LIB_DIRS = + +# +# Flags dealing with installing and uninstalling +# + +# Additional directories to be created during installation +ADDITIONAL_INSTALL_DIRS = \ + $(GNUSTEP_HEADERS)/$(GNUSTEP_FND_DIR)/eoaccess/exceptions + + +# What are the libraries this library depends upon. This is needed for some +# systems where building a shared library requires to pass to the linker +# all the libraries the target library depends upon. + +LIBRARIES_DEPEND_UPON = -l$(FOUNDATION_LIBRARY_NAME) + +ifeq ($(FOUNDATION_HAS_KVC), yes) + ADDITIONAL_OBJCFLAGS := $(ADDITIONAL_OBJCFLAGS) -DFOUNDATION_HAS_KVC=1 +endif diff --git a/EOControl/gdl2control.gsdoc b/EOControl/gdl2control.gsdoc new file mode 100644 index 0000000..c3b133a --- /dev/null +++ b/EOControl/gdl2control.gsdoc @@ -0,0 +1,23 @@ + + + + + GDL2 Control + + + + + + + + + + GDL2 Control +

... +

+
+ + + + +
diff --git a/EOModeler/EOModelExtensions.h b/EOModeler/EOModelExtensions.h new file mode 100644 index 0000000..e23443f --- /dev/null +++ b/EOModeler/EOModelExtensions.h @@ -0,0 +1,77 @@ +/* + EOModelExtensions.h + + Copyright (C) 2001 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: June 2001 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __EOModelExtensions_h__ +#define __EOModelExtensions_h__ + + +#import + + +@interface EOEntity (EOModelExtensions) + +- (NSArray *)classAttributes; +- (NSArray *)classScalarAttributes; +- (NSArray *)classNonScalarAttributes; +- (NSArray *)classToManyRelationships; +- (NSArray *)classToOneRelationships; +- (NSArray *)referencedClasses; +- (NSString *)referenceClassName; +- (NSString *)referenceJavaClassName; + +- (NSString *)parentClassName; +- (NSString *)javaParentClassName; + +- (NSArray *)arrayWithParentClassNameIfNeeded; + +- (NSString *)classNameWithoutPackage; +- (NSArray *)classPackage; + +@end + +@interface EOAttribute (EOModelExtensions) + +- (BOOL)isScalar; +- (NSString *)cScalarTypeString; +- (BOOL)isDeclaredBySuperClass; +- (NSString *)javaValueClassName; + +@end + +@interface EORelationship (EOModelExtensions) + +- (BOOL)isDeclaredBySuperClass; + +@end + +@interface NSMutableAttributedString (_EOModelerErrorConstruction) + ++ (NSMutableAttributedString *)mutableAttributedStringWithBoldSubstitutionsWithFormat:(NSString *)format, ...; + +@end + + +#endif /* __EOModelExtensions_h__ */ diff --git a/EOModeler/EOModelExtensions.m b/EOModeler/EOModelExtensions.m new file mode 100644 index 0000000..c4f35e3 --- /dev/null +++ b/EOModeler/EOModelExtensions.m @@ -0,0 +1,260 @@ +/* + EOModelExtensions.m + + Copyright (C) 2001 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: January 2001 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#import +#import + + +@implementation EOEntity (EOModelExtensions) + +- (NSArray *)classAttributes +{ + NSEnumerator *enumerator = [[self attributes] objectEnumerator]; + EOAttribute *attr; + NSMutableArray *array; + + EOFLOGObjectFnStartOrCond2(@"ModelingClasses",@"EOEntity"); + + array = [NSMutableArray arrayWithCapacity:10]; + + while((attr = [enumerator nextObject])) + { + [array addObject:attr]; + } + + EOFLOGObjectFnStopOrCond2(@"ModelingClasses",@"EOEntity"); + + return array; +} + +- (NSArray *)classScalarAttributes +{ + NSEnumerator *enumerator = [[self attributes] objectEnumerator]; + EOAttribute *attr; + NSMutableArray *array; + + EOFLOGObjectFnStartOrCond2(@"ModelingClasses",@"EOEntity"); + + array = [NSMutableArray arrayWithCapacity:10]; + + while((attr = [enumerator nextObject])) + { + if([attr isScalar] == YES) + [array addObject:attr]; + } + + EOFLOGObjectFnStopOrCond2(@"ModelingClasses",@"EOEntity"); + + return array; +} + +- (NSArray *)classNonScalarAttributes +{ + NSEnumerator *enumerator = [[self attributes] objectEnumerator]; + EOAttribute *attr; + NSMutableArray *array; + + EOFLOGObjectFnStartOrCond2(@"ModelingClasses",@"EOEntity"); + + array = [NSMutableArray arrayWithCapacity:10]; + + while((attr = [enumerator nextObject])) + { + if([attr isScalar] == NO) + [array addObject:attr]; + } + + EOFLOGObjectFnStopOrCond2(@"ModelingClasses",@"EOEntity"); + + return array; +} + +- (NSArray *)classToManyRelationships +{ + NSEnumerator *enumerator = [[self relationships] objectEnumerator]; + EORelationship *relationship; + NSMutableArray *array; + + EOFLOGObjectFnStartOrCond2(@"ModelingClasses",@"EOEntity"); + + array = [NSMutableArray arrayWithCapacity:10]; + + while((relationship = [enumerator nextObject])) + { + if([relationship isToMany] == YES) + [array addObject:relationship]; + } + + EOFLOGObjectFnStopOrCond2(@"ModelingClasses",@"EOEntity"); + + return array; +} + +- (NSArray *)classToOneRelationships +{ + NSEnumerator *enumerator = [[self relationships] objectEnumerator]; + EORelationship *relationship; + NSMutableArray *array; + + EOFLOGObjectFnStartOrCond2(@"ModelingClasses",@"EOEntity"); + + array = [NSMutableArray arrayWithCapacity:10]; + + while((relationship = [enumerator nextObject])) + { + if([relationship isToMany] == NO) + [array addObject:relationship]; + } + + EOFLOGObjectFnStopOrCond2(@"ModelingClasses",@"EOEntity"); + + return array; +} + +- (NSArray *)referencedClasses +{ + NSEnumerator *enumerator = [[self relationships] objectEnumerator]; + EORelationship *relationship; + NSMutableArray *array; + + EOFLOGObjectFnStartOrCond2(@"ModelingClasses",@"EOEntity"); + + array = [NSMutableArray arrayWithCapacity:10]; + + while((relationship = [enumerator nextObject])) + { + [array addObject:[[relationship destinationEntity] className]]; + } + + EOFLOGObjectFnStopOrCond2(@"ModelingClasses",@"EOEntity"); + + return array; +} + +- (NSString *)referenceClassName +{ + if([[self className] isEqual:@"EOGenericRecord"]) + return @"id"; + + return [NSString stringWithFormat:@"%@ *", [self className]]; +} + +- (NSString *)referenceJavaClassName +{ + if([[self className] isEqual:@"EOGenericRecord"]) + return @"CustomObject"; + + return [self className]; +} + +- (NSString *)parentClassName +{ + if([self parentEntity]) + return [[self parentEntity] className]; + + return @"NSObject"; +} + +- (NSString *)javaParentClassName +{ + if([self parentEntity]) + return [[self parentEntity] className]; + + return @"EOCustomObject"; +} + +- (NSArray *)arrayWithParentClassNameIfNeeded +{ + NSMutableArray *array; + + array = [NSMutableArray arrayWithCapacity:1]; + + if([self parentEntity]) + [array addObject:[[self parentEntity] className]]; + + return array; +} + +- (NSString *)classNameWithoutPackage +{ + return [self className]; +} + +- (NSArray *)classPackage +{ + return [NSArray array]; +} + +@end + + +@implementation EOAttribute (EOModelExtensions) + +- (BOOL)isScalar +{ + return NO; +} + +- (NSString *)cScalarTypeString +{ + return nil; +} + +- (BOOL)isDeclaredBySuperClass +{ + return NO; +} + +- (NSString *)javaValueClassName +{ + [self notImplemented:_cmd]; + + return nil; +} + +@end + + +@implementation EORelationship (EOModelExtensions) + +- (BOOL)isDeclaredBySuperClass +{ + return NO; +} + +@end + + +@implementation NSMutableAttributedString (_EOModelerErrorConstruction) + ++ (NSMutableAttributedString *)mutableAttributedStringWithBoldSubstitutionsWithFormat:(NSString *)format, ... +{ + [self notImplemented:_cmd]; + + return nil; +} + +@end diff --git a/EOModeler/GNUmakefile b/EOModeler/GNUmakefile new file mode 100644 index 0000000..a789cbf --- /dev/null +++ b/EOModeler/GNUmakefile @@ -0,0 +1,57 @@ +# +# EOModeler makefile for GNUstep Database Library. +# +# Copyright (C) 2001 Free Software Foundation, Inc. +# +# Written by: Mirko Viviani +# +# This file is part of the GNUstep Database Library. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +# Install into the system root by default +GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_SYSTEM_ROOT) + +GNUSTEP_MAKEFILES = $(GNUSTEP_SYSTEM_ROOT)/Makefiles + +include $(GNUSTEP_MAKEFILES)/common.make + +include ../Version + +# The library to be compiled +LIBRARY_NAME=libgnustep-db2modeler + +libgnustep-db2modeler_LIBRARIES_DEPEND_UPON = -lgnustep-base -lFoundationExt + +# The C source files to be compiled +libgnustep-db2modeler_C_FILES = + +# The Objective-C source files to be compiled +libgnustep-db2modeler_OBJC_FILES = EOModelExtensions.m + +libgnustep-db2modeler_HEADER_FILES_DIR = . +libgnustep-db2modeler_HEADER_FILES_INSTALL_DIR = /EOControl + +libgnustep-db2modeler_HEADER_FILES = EOModelExtensions.h + + +-include Makefile.preamble + +-include GNUmakefile.local + +include $(GNUSTEP_MAKEFILES)/library.make + +-include Makefile.postamble diff --git a/EOModeler/Makefile.postamble b/EOModeler/Makefile.postamble new file mode 100644 index 0000000..0af2e0c --- /dev/null +++ b/EOModeler/Makefile.postamble @@ -0,0 +1,69 @@ +# +# Makefile.postamble +# +# Copyright (C) 1997 Free Software Foundation, Inc. +# +# Written by: Scott Christley +# +# This file is part of the GNUstep Database Library. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +# +# Makefile.postamble +# +# Project specific makefile rules +# +# Uncomment the targets you want. +# The double colons (::) are important, do not make them single colons +# otherwise the normal makefile rules will not be performed. +# + +# Things to do before compiling +before-all:: + +# Things to do after compiling +# after-all:: + +# Things to do before installing +# before-install:: + +# Things to do after installing +# after-install:: + +# Things to do before uninstalling +# before-uninstall:: + +# Things to do after uninstalling +# after-uninstall:: + +# Things to do before cleaning +# before-clean:: + +# Things to do after cleaning +# after-clean:: + +# Things to do before distcleaning +# before-distclean:: + +# Things to do after distcleaning +# after-distclean:: + +# Things to do before checking +# before-check:: + +# Things to do after checking +# after-check: diff --git a/EOModeler/Makefile.preamble b/EOModeler/Makefile.preamble new file mode 100644 index 0000000..11b5304 --- /dev/null +++ b/EOModeler/Makefile.preamble @@ -0,0 +1,69 @@ +# +# Makefile.preamble +# +# Copyright (C) 1997 Free Software Foundation, Inc. +# +# Written by: Scott Christley +# +# This file is part of the GNUstep Database Library. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +# +# Makefile.preamble +# +# Project specific makefile variables, and additional +# +# Do not put any Makefile rules in this file, instead they should +# be put into Makefile.postamble. +# + +# +# Flags dealing with compiling and linking +# + +# Additional flags to pass to the preprocessor +ADDITIONAL_CPPFLAGS = $(FND_DEFINE) $(RUNTIME_DEFINE) + +# Additional flags to pass to the Objective-C compiler +ADDITIONAL_OBJCFLAGS = + +# Additional flags to pass to the C compiler +ADDITIONAL_CFLAGS = + +# Additional include directories the compiler should search +ADDITIONAL_INCLUDE_DIRS = -I.. + +# Additional LDFLAGS to pass to the linker +ADDITIONAL_LDFLAGS = + +# Additional library directories the linker should search +ADDITIONAL_LIB_DIRS = + +# +# Flags dealing with installing and uninstalling +# + +# Additional directories to be created during installation +ADDITIONAL_INSTALL_DIRS = \ + $(GNUSTEP_HEADERS)/$(GNUSTEP_FND_DIR)/eoaccess/exceptions + + +# What are the libraries this library depends upon. This is needed for some +# systems where building a shared library requires to pass to the linker +# all the libraries the target library depends upon. + +LIBRARIES_DEPEND_UPON = -l$(FOUNDATION_LIBRARY_NAME) diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 0000000..5a505fc --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,41 @@ +# +# Main Makefile for GNUstep Database Library. +# +# Copyright (C) 1997 Free Software Foundation, Inc. +# +# Written by: Scott Christley +# +# This file is part of the GNUstep Database Library. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +GNUSTEP_MAKEFILES = $(GNUSTEP_SYSTEM_ROOT)/Makefiles + +include $(GNUSTEP_MAKEFILES)/common.make + +include ./Version + +# +# The list of subproject directories +# +SUBPROJECTS = EOAccess EOControl EOAdaptors EOModeler Tools + +-include Makefile.preamble + +include $(GNUSTEP_MAKEFILES)/aggregate.make + +-include Makefile.postamble + diff --git a/Makefile.postamble b/Makefile.postamble new file mode 100644 index 0000000..8633892 --- /dev/null +++ b/Makefile.postamble @@ -0,0 +1,83 @@ +# -*-makefile-*- +# Makefile.postamble +# +# Copyright (C) 1997 Free Software Foundation, Inc. +# +# Written by: Scott Christley +# +# This file is part of the GNUstep Database Library. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +# +# Makefile.postamble +# +# Project specific makefile rules +# +# Uncomment the targets you want. +# The double colons (::) are important, do not make them single colons +# otherwise the normal makefile rules will not be performed. +# + +# Things to do before compiling +# before-all:: + +# Things to do after compiling +# after-all:: + +# Things to do before installing +# before-install:: + +# +# The following rule is important mainly for packaging, because in that case +# you install into a fake system tree, and the directory is not there. +# + +$(INSTALL_ROOT_DIR)$(GNUSTEP_MAKEFILES)/Auxiliary: + $(MKINSTALLDIRS) $@ + +# Things to do after installing +after-install:: $(INSTALL_ROOT_DIR)$(GNUSTEP_MAKEFILES)/Auxiliary + $(INSTALL_DATA) gdl2.make \ + $(INSTALL_ROOT_DIR)$(GNUSTEP_MAKEFILES)/Auxiliary/gdl2.make + +# Things to do before uninstalling +# before-uninstall:: + +# Things to do after uninstalling +after-uninstall:: + rm -f $(INSTALL_ROOT_DIR)$(GNUSTEP_MAKEFILES)/Auxiliary/gdl2.make + +# Things to do before cleaning +# before-clean:: + +# Things to do after cleaning +# after-clean:: + +# Things to do before distcleaning +# before-distclean:: + +# Things to do after distcleaning +after-distclean:: + rm -rf config.cache config.log config.status + rm -rf config.h gdl2.make + +# Things to do before checking +# before-check:: + +# Things to do after checking +# after-check:: + diff --git a/TODO b/TODO new file mode 100644 index 0000000..c6fed81 --- /dev/null +++ b/TODO @@ -0,0 +1,20 @@ +DB Contextex +initializeObject:(id)object//<%EOGenericRecord[Payment](0x2f4f940)> + row:(NSDictionary*)row//0x2f3dae0 + entity:(EOEntity*)entity + editingContext:(EOEditingContext*)context + +New class ? +EOAccessDeferredFaultHandler +EOSQLQualifier + +Class _EODotPathString +_string=NSString * object:0x4adb74 Description:testIt.count +_prefix=NSString * object:0x19ea920 Description:testIt +_suffix=NSString * object:0x19e1a48 Description:count + + + +http://developer.apple.com/techpubs/macosx/Cocoa/Reference/Foundation/Java/Classes/NSKeyValue.html + +http://developer.apple.com/techpubs/macosx/Cocoa/TasksAndConcepts/ProgrammingTopics/KeyValueCoding/Concepts/basicprinciples.html diff --git a/Tools/EOAttribute+GSDoc.h b/Tools/EOAttribute+GSDoc.h new file mode 100644 index 0000000..ed6f06f --- /dev/null +++ b/Tools/EOAttribute+GSDoc.h @@ -0,0 +1,50 @@ +/* + EOAttribute+GSDoc.h + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: August 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +// $Id$ + +#ifndef __EOAttribute_GSDoc_h__ +#define __EOAttribute_GSDoc_h__ + +#include + + +@interface EOAttribute (GSDoc) + +- (NSString *)gsdocContentWithIdPtr: (int *)xmlIdPtr; +- (NSString *)gsdocContentWithTagName: (NSString *)tagName; + +@end + + +#endif /* __EOAttribute_GSDoc_h__ */ diff --git a/Tools/EOAttribute+GSDoc.m b/Tools/EOAttribute+GSDoc.m new file mode 100644 index 0000000..fb08384 --- /dev/null +++ b/Tools/EOAttribute+GSDoc.m @@ -0,0 +1,133 @@ +/* + EOAttribute+GSDoc.m + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: August 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#include +#include +#include +#include +#include "NSArray+GSDoc.h" +#include "NSDictionary+GSDoc.h" +#include "EOAttribute+GSDoc.h" + +/* + NSString* calendarFormat; + NSTimeZone* clientTimeZone; + NSTimeZone* serverTimeZone; + NSString* insertFormat; + NSString* selectFormat; + NSString* updateFormat; + GCMutableArray* definitionArray; // These variables are meaningful only + EOAttribute* realAttribute; // if the attribute is flattened + +*/ + +@implementation EOAttribute (GSDoc) + +- (NSString *)gsdocContentWithIdPtr: (int *)xmlIdPtr; +{ + return [self gsdocContentWithTagName: @"EOAttribute" + idPtr: xmlIdPtr]; +} + +- (NSString *)gsdocContentWithTagName: (NSString *)tagName + idPtr: (int *)xmlIdPtr +{ + NSAutoreleasePool *arp = [NSAutoreleasePool new]; + NSString *content = [NSString string]; + + NSLog(@"Start: %@: %@ tagName=%@", [self class], [self name], tagName); + + if ([tagName isEqual: @"EOAttributeRef"]) + { + content = [content stringByAppendingFormat: + @"\n", + [self name], + (xmlIdPtr ? [NSString stringWithFormat: + @" debugId=\"%d\"", + (*xmlIdPtr)++] : @"")]; + } + else + { + content = [content stringByAppendingFormat: + @"<%@%@%@%@%@%@%@%@%@%@%@>\n", + tagName, + ([self columnName] + ? [NSString stringWithFormat: @" columnName=\"%@\"", + [self columnName]] : @""), + ([self definition] + ? [NSString stringWithFormat: @" definition=\"%@\"", + [self definition]] : @""), + ([self externalType] + ? [NSString stringWithFormat: @" externalType=\"%@\"", + [self externalType]] : @""), + ([self name] + ? [NSString stringWithFormat: @" name=\"%@\"", + [self name]] : @""), + ([self valueClassName] + ? [NSString stringWithFormat: + @" valueClassName=\"%@\"", + [self valueClassName]] : @""), + ([self valueType] + ? [NSString stringWithFormat: @" valueType=\"%@\"", + [self valueType]] : @""), + ([[self entity] name] + ? [NSString stringWithFormat: @" entityName=\"%@\"", + [[self entity] name]] : @""), + ([self isReadOnly] ? @" isReadOnly=\"YES\"" : @""), + ([self isDerived] ? @" isDerived=\"YES\"" : @""), + ([self isFlattened] ? @" isFlattened=\"YES\"" : @"")]; + + if ([[self userInfo] count]) + content = [content stringByAppendingString: + [[self userInfo] + gsdocContentWithTagName: @"EOUserDictionary" + idPtr: xmlIdPtr]]; + if ([self docComment]) + content = [content stringByAppendingFormat: @"%@\n", + [self docComment]]; + + content = [content stringByAppendingFormat: @"\n", + tagName]; + } + + NSLog(@"Stop: %@: %@", [self class], [self name]); + + RETAIN(content); + DESTROY(arp); + + return AUTORELEASE(content); +} + +@end diff --git a/Tools/EOEntity+GSDoc.h b/Tools/EOEntity+GSDoc.h new file mode 100644 index 0000000..c36e28d --- /dev/null +++ b/Tools/EOEntity+GSDoc.h @@ -0,0 +1,48 @@ +/** + EOEntity+GSDoc.h + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: August 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +// $Id$ + +#ifndef __EOEntity_GSDoc_h__ +#define __EOEntity_GSDoc_h__ + +#include + +@interface EOEntity (GSDoc) + +- (NSString *)gsdocContentWithIdPtr: (int *)xmlIdPtr; + +@end + + +#endif /* __EOEntity_GSDoc_h__ */ diff --git a/Tools/EOEntity+GSDoc.m b/Tools/EOEntity+GSDoc.m new file mode 100644 index 0000000..5c18603 --- /dev/null +++ b/Tools/EOEntity+GSDoc.m @@ -0,0 +1,133 @@ +/* + EOEntity+GSDoc.m + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: August 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#include +#include +#include +#include "NSArray+GSDoc.h" +#include "NSDictionary+GSDoc.h" +#include "EOModel+GSDoc.h" +#include "EOEntity+GSDoc.h" + +/* + NSString* externalQuery; + NSArray* attributesNamesUsedForInsert; + EOQualifier* qualifier; + GCArray* attributesUsedForInsert; // cache from classProperties + GCArray* attributesUsedForFetch; // cache from classProperties + GCArray* relationsUsedForFetch; // cache from classProperties +*/ + +@implementation EOEntity (GSDoc) + +- (NSString *)gsdocContentWithIdPtr: (int *)xmlIdPtr +{ + NSAutoreleasePool *arp = [NSAutoreleasePool new]; + NSString *content = [NSString string]; + + NSLog(@"Start: %@: %@", [self class], [self name]); + + content = [content stringByAppendingFormat: @"\n", + (xmlIdPtr ? [NSString stringWithFormat: + @" debugId=\"%d\"", + (*xmlIdPtr)++] : @""), + ([self name] + ? [NSString stringWithFormat: @" name=\"%@\"", + [self name]] : @""), + ([self externalName] + ? [NSString stringWithFormat: @" externalName=\"%@\"", + [self externalName]] : @""), + ([self className] + ? [NSString stringWithFormat: @" className=\"%@\"", + [self className]] : @""), + ([[self model] name] + ? [NSString stringWithFormat: @" modelName=\"%@\"", + [[self model] name]] : @""), + ([self isReadOnly] ? @"isReadOnly=\"YES\"" : @"")]; + + if ([self attributes]) + content = [content stringByAppendingString: [[self attributes] + gsdocContentWithTagName: nil + idPtr: xmlIdPtr]]; + + if ([self attributesUsedForLocking]) + content = [content stringByAppendingString: + [[self attributesUsedForLocking] + gsdocContentWithTagName: + @"EOAttributesUsedForLocking" + elementsTagName: @"EOAttributeRef" + idPtr: xmlIdPtr]]; + + if ([self classProperties]) + content = [content stringByAppendingString: + [[self classProperties] + gsdocContentWithTagName: @"EOClassProperties" + elementsTagName: @"EOAttributeRef" + idPtr: xmlIdPtr]]; + + if ([self primaryKeyAttributes]) + content = [content stringByAppendingString: + [[self primaryKeyAttributes] + gsdocContentWithTagName: + @"EOPrimaryKeyAttributes" + elementsTagName: @"EOAttributeRef" + idPtr: xmlIdPtr]]; + + if ([self relationships]) + content = [content stringByAppendingString: [[self relationships] + gsdocContentWithTagName: nil + idPtr: xmlIdPtr]]; + + if ([[self userInfo] count]) + content = [content stringByAppendingString: + [[self userInfo] + gsdocContentWithTagName: @"EOUserDictionary" + idPtr: xmlIdPtr]]; + + if ([self docComment]) + content = [content stringByAppendingFormat: @"%@\n", + [self docComment]]; + + content = [content stringByAppendingString: @"
\n"]; + + NSLog(@"Stop: %@: %@", [self class], [self name]); + + RETAIN(content); + DESTROY(arp); + + return AUTORELEASE(content); +} + +@end diff --git a/Tools/EOJoin+GSDoc.h b/Tools/EOJoin+GSDoc.h new file mode 100644 index 0000000..31e047a --- /dev/null +++ b/Tools/EOJoin+GSDoc.h @@ -0,0 +1,48 @@ +/** + EOJoin+GSDoc.h EOJoin+GSDoc + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: August 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +// $Id$ + +#ifndef __EOJoin_GSDoc_h__ +#define __EOJoin_GSDoc_h__ + +#include + +@interface EOJoin (GSDoc) + +- (NSString *)gsdocContentWithIdPtr: (int *)xmlIdPtr; + +@end + + +#endif /* __EOJoin_GSDoc_h__ */ diff --git a/Tools/EOJoin+GSDoc.m b/Tools/EOJoin+GSDoc.m new file mode 100644 index 0000000..8fcaf3e --- /dev/null +++ b/Tools/EOJoin+GSDoc.m @@ -0,0 +1,79 @@ +/** + EOJoin+GSDoc.m EOJoin+GSDoc + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: August 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#include +#include +#include +#include +#include "NSArray+GSDoc.h" +#include "NSDictionary+GSDoc.h" +#include "EOAttribute+GSDoc.h" +#include "EOJoin+GSDoc.h" + + +@implementation EOJoin (GSDoc) + +- (NSString *)gsdocContentWithIdPtr: (int *)xmlIdPtr +{ + NSAutoreleasePool *arp = [NSAutoreleasePool new]; + NSString *content = [NSString string]; + + NSLog(@"Start: %@", [self class]); + + content = [content stringByAppendingFormat: + @"\n", + (xmlIdPtr + ? [NSString stringWithFormat: @" debugId=\"%d\"", + (*xmlIdPtr)++] : @""), + @"",//[[self relationship] name], + @"",//[self joinOperatorDescription], + @"",//[self joinSemanticDescription], + [[self sourceAttribute] name], + [[self destinationAttribute] name]]; + + /* if ([self docComment]) + content=[content stringByAppendingFormat:@"%@\n",[self docComment]];*/ + + content = [content stringByAppendingString: @"\n"]; + + NSLog(@"Stop: %@", [self class]); + + RETAIN(content); + DESTROY(arp); + + return AUTORELEASE(content); +} + +@end diff --git a/Tools/EOModel+GSDoc.h b/Tools/EOModel+GSDoc.h new file mode 100644 index 0000000..f4f8f1b --- /dev/null +++ b/Tools/EOModel+GSDoc.h @@ -0,0 +1,51 @@ +/** + EOModel+GSDoc.h + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: August 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +// $Id$ + +#ifndef __EOModel_GSDoc_h__ +#define __EOModel_GSDoc_h__ + +#include + + +@interface EOModel (GSDoc) + +- (NSString *)gsdocContentWithIdPtr: (int *)xmlIdPtr; +- (NSString *)gsdocContentSplittedByEntities: (NSDictionary **)entitiesPtr + withIdPtr: (int *)xmlIdPtr; + +@end + + +#endif /* __EOModel_GSDoc_h__ */ diff --git a/Tools/EOModel+GSDoc.m b/Tools/EOModel+GSDoc.m new file mode 100644 index 0000000..1551d0d --- /dev/null +++ b/Tools/EOModel+GSDoc.m @@ -0,0 +1,149 @@ +/** + EOModel+GSDoc.m + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: August 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#include +#include +#include +#include +#include +#include +#include "NSArray+GSDoc.h" +#include "NSDictionary+GSDoc.h" +#include "EOEntity+GSDoc.h" +#include "EOModel+GSDoc.h" + + +@implementation EOModel (GSDoc) + +- (NSString *)gsdocContentWithIdPtr: (int *)xmlIdPtr +{ + return [self gsdocContentSplittedByEntities: NULL + idPtr: xmlIdPtr]; +} + +- (NSString *)gsdocContentSplittedByEntities: (NSDictionary **)entitiesPtr + withIdPtr: (int *)xmlIdPtr +{ + NSAutoreleasePool *arp = [NSAutoreleasePool new]; + NSString *content = [NSString string]; + NSArray *entities = [self entities]; + int i, count = [entities count]; + + NSLog(@"Start: %@", [self class]); + + content = [content stringByAppendingFormat: + @"\nEOModel %@\n\n", + ([self name] + ? [NSString stringWithFormat: @" id=\"%@\"", + [self name]] : @""), + ([self name] ? [self name] : @""), + (xmlIdPtr + ? [NSString stringWithFormat: @" debugId=\"%d\"", + (*xmlIdPtr)++] : @""), + ([self name] + ? [NSString stringWithFormat: @" name=\"%@\"", + [self name]] : @""), + ([self version] + ? [NSString stringWithFormat: @" version=\"%f\"", + [self version]] : @""), + ([self adaptorName] + ? [NSString stringWithFormat: @" adaptorName=\"%@\"", + [self adaptorName]] : @""), + ([self adaptorClassName] + ? [NSString stringWithFormat: @" adaptorClassName=\"%@\"", + [self adaptorClassName]] + : @" adaptorClassName=\"\"")]; + + if ([self connectionDictionary]) + content = [content stringByAppendingString: + [[self connectionDictionary] + gsdocContentWithTagName: @"EOConnectionDictionary" + idPtr: xmlIdPtr]]; + + if (entitiesPtr) + { + *entitiesPtr = [NSMutableDictionary dictionary]; + content = [content stringByAppendingString: @"[[entities]]"]; + } + + for (i = 0; i < count; i++) + { + EOEntity *entity = [entities objectAtIndex: i]; + NSString *entityContent = [entity gsdocContentWithIdPtr: xmlIdPtr]; + + NSAssert(entityContent, @"No entity gsdoc content"); + + if (entitiesPtr) + { + entityContent = [NSString stringWithFormat: + @"\nEOEntity %@\n%@\n\n", + [entity name], + [entity name], + entityContent]; + [(NSMutableDictionary*)*entitiesPtr setObject: entityContent + forKey: [entity name]]; + } + else + content = [content stringByAppendingString: entityContent]; + } + + if ([[self userInfo] count]) + content = [content stringByAppendingString: + [[self userInfo] + gsdocContentWithTagName: @"EOUserDictionary" + idPtr: xmlIdPtr]]; + + if ([self docComment]) + content = [content stringByAppendingFormat: @"%@\n", + [self docComment]]; + + content = [content stringByAppendingString: @"\n\n"]; + + NSLog(@"Stop: %@", [self class]); + + RETAIN(content); + + if (entitiesPtr) + RETAIN(*entitiesPtr); + + DESTROY(arp); + + if (entitiesPtr) + AUTORELEASE(*entitiesPtr); + + return AUTORELEASE(content); +} + +@end diff --git a/Tools/EORelationship+GSDoc.h b/Tools/EORelationship+GSDoc.h new file mode 100644 index 0000000..ea3fad4 --- /dev/null +++ b/Tools/EORelationship+GSDoc.h @@ -0,0 +1,50 @@ +/** + EORelationship+GSDoc.h + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: August 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +// $Id$ + +#ifndef __EORelationship_GSDoc_h__ +#define __EORelationship_GSDoc_h__ + +#include + +@interface EORelationship (GSDoc) + +- (NSString *)gsdocContentWithIdPtr: (int *)xmlIdPtr; +- (NSString *)gsdocContentWithTagName: (NSString *)tagName + idPtr: (int *)xmlIdPtr; + +@end + + +#endif /* __EORelationship_GSDoc_h__ */ diff --git a/Tools/EORelationship+GSDoc.m b/Tools/EORelationship+GSDoc.m new file mode 100644 index 0000000..cad2c26 --- /dev/null +++ b/Tools/EORelationship+GSDoc.m @@ -0,0 +1,139 @@ +/** + EORelationship+GSDoc.m + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: August 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#include +#include +#include +#include +#include "NSArray+GSDoc.h" +#include "NSDictionary+GSDoc.h" +#include "EORelationship+GSDoc.h" + +/* + NSString* definition; + struct { + BOOL isFlattened:1; + BOOL isToMany:1; + BOOL createsMutableObjects:1; + } flags; +*/ + + +@implementation EORelationship (GSDoc) + +- (NSString *)gsdocContentWithIdPtr: (int *)xmlIdPtr +{ + return [self gsdocContentWithTagName: @"EORelationship" + idPtr: xmlIdPtr]; +} + +- (NSString *)gsdocContentWithTagName: (NSString *)tagName + idPtr: (int *)xmlIdPtr +{ + NSAutoreleasePool *arp = [NSAutoreleasePool new]; + NSString *content = [NSString string]; + + NSLog(@"Start: %@: %@", [self class], [self name]); + + if ([tagName isEqual: @"EOAttributeRef"]) + { + content = [content stringByAppendingFormat: + @"\n", + (xmlIdPtr + ? [NSString stringWithFormat: @" debugId=\"%d\"", + (*xmlIdPtr)++] : @""), + [self name]]; + } + else + { + content = [content stringByAppendingFormat: + @"<%@%@ name=\"%@\" entityName=\"%@\" destinationEntityName=\"%@\">\n", + tagName, + (xmlIdPtr + ? [NSString stringWithFormat: @" id=\"%d\"", + (*xmlIdPtr)++] : @""), + [self name], + [[self entity] name], + [[self destinationEntity] name]]; + + if ([self isFlattened]) + { + int i, count = [[self componentRelationships] count]; + + for (i = 0; i < count; i++) + { + id component = [[self componentRelationships] objectAtIndex: i]; + + content = [content stringByAppendingFormat: + @"\n", + (xmlIdPtr + ? [NSString stringWithFormat: @" id=\"%d\"", + (*xmlIdPtr)++] : @""), + [component name]]; + } + + for (i = 0; i < count; i++) + content = [content stringByAppendingString: + @"\n"]; + } + else if ([self joins]) + content = [content stringByAppendingString: + [[self joins] + gsdocContentWithTagName: nil + idPtr: xmlIdPtr]]; + + if ([[self userInfo] count]) + content = [content stringByAppendingString: + [[self userInfo] + gsdocContentWithTagName: @"EOUserDictionary" + idPtr: xmlIdPtr]]; + + if ([self docComment]) + content = [content stringByAppendingFormat: @"%@\n", + [self docComment]]; + + content = [content stringByAppendingFormat: @"\n", + tagName]; + } + + NSLog(@"Stop: %@: %@", [self class], [self name]); + + RETAIN(content); + DESTROY(arp); + + return AUTORELEASE(content); +} + +@end diff --git a/Tools/GNUmakefile b/Tools/GNUmakefile new file mode 100644 index 0000000..fc851b8 --- /dev/null +++ b/Tools/GNUmakefile @@ -0,0 +1,96 @@ +# +# EOAccess makefile for GNUstep Database Library. +# +# Copyright (C) 1997 Free Software Foundation, Inc. +# +# Written by: Scott Christley +# +# This file is part of the GNUstep Database Library. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +# Install into the system root by default +GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_SYSTEM_ROOT) + +GNUSTEP_MAKEFILES = $(GNUSTEP_SYSTEM_ROOT)/Makefiles + +include $(GNUSTEP_MAKEFILES)/common.make + +include ../Version + +# The library to be compiled +TOOL_NAME=gdlgsdoc + +LIBRARIES_DEPEND_UPON=-lgnustep-base -lFoundationExt -lgnustep-db2control -lgnustep-db2 + +# The C source files to be compiled +gdlgsdoc_C_FILES = + +# The Objective-C source files to be compiled +gdlgsdoc_OBJC_FILES = \ +EOAttribute+GSDoc.m \ +EOEntity+GSDoc.m \ +EOJoin+GSDoc.m \ +EOModel+GSDoc.m \ +EORelationship+GSDoc.m \ +gsdoc-model.m \ +NSArray+GSDoc.m \ +NSDictionary+GSDoc.m \ + +gdlgsdoc_HEADER_FILES_DIR = . +#gdlgsdoc_HEADER_FILES_INSTALL_DIR = + +gdlgsdoc_HEADER_FILES = \ +EOAttribute+GSDoc.h \ +EOEntity+GSDoc.h \ +EOJoin+GSDoc.h \ +EOModel+GSDoc.h \ +EORelationship+GSDoc.h \ +NSArray+GSDoc.h \ +NSDictionary+GSDoc.h \ + +gdl2gsdoc_AUTOGSDOC_HEADERS = $(gdlgsdoc_HEADER_FILES) +gdl2gsdoc_AUTOGSDOC_SOURCE = $(gdlgsdoc_OBJC_FILES) +DOCUMENT_NAME = gdl2gsdoc +gdl2gsdoc_HEADER_FILES_DIR = $(HEADER_DIR) +gdl2gsdoc_AGSDOC_FILES = gdl2gsdoc.gsdoc $(gdl2gsdoc_AUTOGSDOC_HEADERS) +#$(gdl2gsdoc_AUTOGSDOC_SOURCE) +gdl2gsdoc_AGSDOC_FLAGS = \ + -Declared gdlgsdoc \ + -Standards YES \ + -Project gdl2gsdoc \ + -WordMap '{\ + FOUNDATION_EXPORT=extern;FOUNDATION_STATIC_INLINE="";\ + GS_GEOM_SCOPE=extern;GS_GEOM_ATTR="";\ + GS_EXPORT=extern;GS_DECLARE="";\ + GS_RANGE_SCOPE=extern;GS_RANGE_ATTR="";\ + GS_ZONE_SCOPE=extern;GS_ZONE_ATTR="";\ + }' -Up gdl2gsdoc + + +-include Makefile.preamble + +-include GNUmakefile.local + +include $(GNUSTEP_MAKEFILES)/tool.make +include $(GNUSTEP_MAKEFILES)/ctool.make +# Only build the doc if doc=yes was passed on the command line +ifeq ($(doc),yes) +include $(GNUSTEP_MAKEFILES)/documentation.make +endif + + +-include Makefile.postamble diff --git a/Tools/Makefile.postamble b/Tools/Makefile.postamble new file mode 100644 index 0000000..0af2e0c --- /dev/null +++ b/Tools/Makefile.postamble @@ -0,0 +1,69 @@ +# +# Makefile.postamble +# +# Copyright (C) 1997 Free Software Foundation, Inc. +# +# Written by: Scott Christley +# +# This file is part of the GNUstep Database Library. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +# +# Makefile.postamble +# +# Project specific makefile rules +# +# Uncomment the targets you want. +# The double colons (::) are important, do not make them single colons +# otherwise the normal makefile rules will not be performed. +# + +# Things to do before compiling +before-all:: + +# Things to do after compiling +# after-all:: + +# Things to do before installing +# before-install:: + +# Things to do after installing +# after-install:: + +# Things to do before uninstalling +# before-uninstall:: + +# Things to do after uninstalling +# after-uninstall:: + +# Things to do before cleaning +# before-clean:: + +# Things to do after cleaning +# after-clean:: + +# Things to do before distcleaning +# before-distclean:: + +# Things to do after distcleaning +# after-distclean:: + +# Things to do before checking +# before-check:: + +# Things to do after checking +# after-check: diff --git a/Tools/Makefile.preamble b/Tools/Makefile.preamble new file mode 100644 index 0000000..fe7f568 --- /dev/null +++ b/Tools/Makefile.preamble @@ -0,0 +1,77 @@ +# +# Makefile.preamble +# +# Copyright (C) 1997 Free Software Foundation, Inc. +# +# Written by: Scott Christley +# +# This file is part of the GNUstep Database Library. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +# +# Makefile.preamble +# +# Project specific makefile variables, and additional +# +# Do not put any Makefile rules in this file, instead they should +# be put into Makefile.postamble. +# + +# +# Flags dealing with compiling and linking +# + +# Additional flags to pass to the preprocessor +#ADDITIONAL_CPPFLAGS = $(FND_DEFINE) $(RUNTIME_DEFINE) -g + +# Additional flags to pass to the Objective-C compiler +ADDITIONAL_OBJCFLAGS += -Wall + +# Additional flags to pass to the C compiler +ADDITIONAL_CFLAGS = + +# Additional include directories the compiler should search +ADDITIONAL_INCLUDE_DIRS = -I.. + +# Additional LDFLAGS to pass to the linker +ifeq ($(debug), yes) + ADDITIONAL_LDFLAGS := $(ADDITIONAL_LDFLAGS) -lFoundationExt_d -lgnustep-db2_d -lgnustep-db2control_d +else + ADDITIONAL_LDFLAGS := $(ADDITIONAL_LDFLAGS) -lFoundationExt -lgnustep-db2 -lgnustep-db2control +endif + +# Additional library directories the linker should search +ADDITIONAL_LIB_DIRS += -L../EOAccess/$(GNUSTEP_OBJ_DIR) -L../EOControl/$(GNUSTEP_OBJ_DIR) + + +# +# Flags dealing with installing and uninstalling +# + +# Additional directories to be created during installation +ADDITIONAL_INSTALL_DIRS = + + +# What are the libraries this library depends upon. This is needed for some +# systems where building a shared library requires to pass to the linker +# all the libraries the target library depends upon. + +LIBRARIES_DEPEND_UPON = -l$(FOUNDATION_LIBRARY_NAME) + +ifeq ($(FOUNDATION_HAS_KVC), yes) + ADDITIONAL_OBJCFLAGS := $(ADDITIONAL_OBJCFLAGS) -DFOUNDATION_HAS_KVC=1 +endif diff --git a/Tools/NSArray+GSDoc.h b/Tools/NSArray+GSDoc.h new file mode 100644 index 0000000..042f5f0 --- /dev/null +++ b/Tools/NSArray+GSDoc.h @@ -0,0 +1,54 @@ +/** + NSArray+GSDoc.h + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: August 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +// $Id$ + +#ifndef __NSArray_GSDoc_h__ +#define __NSArray_GSDoc_h__ + +#include + + +@interface NSArray (GSDoc) + +- (NSString *)gsdocContentWithIdPtr: (int *)xmlIdPtr; +- (NSString *)gsdocContentWithTagName: (NSString *)tagName + idPtr: (int *)xmlIdPtr; +- (NSString *)gsdocContentWithTagName: (NSString *)tagName + elementsTagName: (NSString *)elementsTagName + idPtr: (int *)xmlIdPtr; + +@end + + +#endif /* __NSArray_GSDoc_h__ */ diff --git a/Tools/NSArray+GSDoc.m b/Tools/NSArray+GSDoc.m new file mode 100644 index 0000000..15ef250 --- /dev/null +++ b/Tools/NSArray+GSDoc.m @@ -0,0 +1,117 @@ +/** + NSArray+GSDoc.m + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: August 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#include +#include +#include "NSArray+GSDoc.h" + + +@implementation NSArray (GSDoc) + +- (NSString *)gsdocContentWithIdPtr: (int *)xmlIdPtr +{ + return [self gsdocContentWithTagName: @"list" + idPtr: NULL]; +} + +- (NSString *)gsdocContentWithTagName: (NSString *)tagName + idPtr: (int *)xmlIdPtr +{ + return [self gsdocContentWithTagName: (NSString *)tagName + elementsTagName: nil + idPtr: xmlIdPtr]; +} + +- (NSString *)gsdocContentWithTagName: (NSString *)tagName + elementsTagName: (NSString *)elementsTagName + idPtr: (int *)xmlIdPtr +{ + NSAutoreleasePool *arp = [NSAutoreleasePool new]; + NSString *content = [NSString string]; + int i, count = [self count]; + + NSLog(@"Start: %@", [self class]); + + if (tagName) + content = [content stringByAppendingFormat: @"<%@%@>\n", + tagName, + (!xmlIdPtr + || [tagName isEqualToString:@"list"] ? @"" + : [NSString stringWithFormat: @" debugId=\"%d\"", + (*xmlIdPtr)++])]; + + for (i = 0; i < count; i++) + { + id elem = [self objectAtIndex: i]; + + NSLog(@"elem: %@", elem); + + if (elementsTagName) + { + if ([elem respondsToSelector: @selector(gsdocContentWithTagName:idPtr:)]) + content = [content stringByAppendingString: + [elem gsdocContentWithTagName: elementsTagName + idPtr: xmlIdPtr]]; + else if ([elem respondsToSelector: @selector(gsdocContentWithIdPtr:)]) + content = [content stringByAppendingString: + [elem gsdocContentWithIdPtr: xmlIdPtr]]; + else + content = [content stringByAppendingFormat: @"%@\n", + elem]; + } + else + { + if ([elem respondsToSelector: @selector(gsdocContentWithIdPtr:)]) + content = [content stringByAppendingString: + [elem gsdocContentWithIdPtr: xmlIdPtr]]; + else + content = [content stringByAppendingFormat: @"%@\n", + elem]; + } + } + + if (tagName) + content = [content stringByAppendingFormat: @"\n", + tagName]; + + NSLog(@"Stop: %@", [self class]); + + RETAIN(content); + DESTROY(arp); + + return AUTORELEASE(content); +} + +@end diff --git a/Tools/NSDictionary+GSDoc.h b/Tools/NSDictionary+GSDoc.h new file mode 100644 index 0000000..424c4db --- /dev/null +++ b/Tools/NSDictionary+GSDoc.h @@ -0,0 +1,51 @@ +/** + NSDictionary+GSDoc.h + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: August 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +// $Id$ + +#ifndef __NSDictionary_GSDoc_h__ +#define __NSDictionary_GSDoc_h__ + +#include + + +@interface NSDictionary (GSDoc) + +- (NSString *)gsdocContentWithIdPtr: (int *)xmlIdPtr; +- (NSString *)gsdocContentWithTagName: (NSString *)tagName + idPtr: (int *)xmlIdPtr; + +@end + + +#endif /* __NSDictionary_GSDoc_h__ */ diff --git a/Tools/NSDictionary+GSDoc.m b/Tools/NSDictionary+GSDoc.m new file mode 100644 index 0000000..e845dea --- /dev/null +++ b/Tools/NSDictionary+GSDoc.m @@ -0,0 +1,97 @@ +/** + NSDictionary+GSDoc.m + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Author: Manuel Guesdon + Date: August 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#include +#include +#include "NSDictionary+GSDoc.h" + + +@implementation NSDictionary (GSDoc) + +- (NSString *)gsdocContentWithIdPtr: (int *)xmlIdPtr +{ + return [self gsdocContentWithTagName: @"dictionary" + idPtr: xmlIdPtr]; +} + +- (NSString *)gsdocContentWithTagName: (NSString *)tagName + idPtr: (int *)xmlIdPtr +{ + NSAutoreleasePool *arp = [NSAutoreleasePool new]; + NSString *content = [NSString string]; + NSEnumerator *enumerator = [self keyEnumerator]; + id key = nil; + + NSLog(@"Start: %@", [self class]); + + if (tagName) + content = [content stringByAppendingFormat: @"<%@%@>\n", + tagName, + (!xmlIdPtr + || [tagName isEqualToString: @"dictionary"] ? @"" + : [NSString stringWithFormat: @" debugId=\"%d\"", + (*xmlIdPtr)++])]; + + while ((key = [enumerator nextObject])) + { + id elem = [self objectForKey: key]; + + NSLog(@"key: %@ elem: %@", key, elem); + + if ([elem respondsToSelector: @selector(gsdocContentWithIdPtr:)]) + content = [content stringByAppendingFormat: + @"\n%@\n", + key, + [elem gsdocContentWithIdPtr: xmlIdPtr]]; + else + content = [content stringByAppendingFormat: + @"\n", + key, + elem]; + } + + if (tagName) + content = [content stringByAppendingFormat: @"\n", + tagName]; + + NSLog(@"Stop: %@", [self class]); + + RETAIN(content); + DESTROY(arp); + + return AUTORELEASE(content); +} + +@end diff --git a/Tools/eomodeltemplate.gsdoc b/Tools/eomodeltemplate.gsdoc new file mode 100644 index 0000000..fc60d1c --- /dev/null +++ b/Tools/eomodeltemplate.gsdoc @@ -0,0 +1,23 @@ + + + + + [[projectName]] + + + + [[infoDictionary.authorDesc]] + + [[infoDictionary.version]] + [[infoDictionary.date]] [[timestampString]] + + [Source : [[fileName]]] DTD] + + [[infoDictionary.copyright]] + + + [[content]] + + + + diff --git a/Tools/gdl2gsdoc.gsdoc b/Tools/gdl2gsdoc.gsdoc new file mode 100644 index 0000000..80785b0 --- /dev/null +++ b/Tools/gdl2gsdoc.gsdoc @@ -0,0 +1,20 @@ + + + + + GDL2 GSDoc + + + + + + + GDL2 GSDoc +

... +

+
+ + + + +
diff --git a/Tools/gsdoc-model.m b/Tools/gsdoc-model.m new file mode 100644 index 0000000..3860826 --- /dev/null +++ b/Tools/gsdoc-model.m @@ -0,0 +1,515 @@ +/* This tool produce .gsdoc files from eomodel files + + Copyright (C) 2000-2002 Free Software Foundation, Inc. + + Written by: Manuel Guesdon + Created: August 2000 + + $Revision$ + $Date$ + + + + This file is part of the GNUstep Database Library. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +**/ + +static char rcsId[] = "$Id$"; + +#include +#include +#include +#include "EOModel+GSDoc.h" + + +NSString *PathExtension_GSDoc = @"gsdoc"; +NSString *PathExtension_EOModel = @"eomodeld"; +NSString *PathExtension_Model = @"model"; +int verbose = 0; + +//-------------------------------------------------------------------- +// In text, replace keys from variables with their values +// variables is like something like this +// { +// "[[key1]]" = "value1"; +// "[[key2]]" = "value2"; +// }; + +NSString *TextByReplacingVariablesInText(NSString *text, + NSDictionary *variables) +{ + NSEnumerator *variablesEnum = [variables keyEnumerator]; + id key; + + while ((key = [variablesEnum nextObject])) + { + id value = [variables objectForKey: key]; + + text = [text stringByReplacingString: key + withString: [value description]]; + } + + return text; +} + +//-------------------------------------------------------------------- +// Return list of files found in dir (deep search) which have extension extension +NSArray *FilesInPathWithExtension(NSString *dir, NSString *extension) +{ + NSMutableArray *files = [NSMutableArray array]; + NSString *file = nil; + NSFileManager *fm = [NSFileManager defaultManager]; + NSDirectoryEnumerator *enumerator = [fm enumeratorAtPath: dir]; + + while ((file = [enumerator nextObject])) + { + BOOL isDirectory = NO; + + file = [dir stringByAppendingPathComponent: file]; + + if ([[file pathExtension] isEqual: extension]) + { + if ([fm fileExistsAtPath: file isDirectory: &isDirectory]) + { + if (!isDirectory) + { + [files addObject: file]; + } + } + } + } + + return files; +} + +//-------------------------------------------------------------------- +int +main(int argc, char **argv, char **env) +{ + NSProcessInfo *proc; + NSArray *args; + unsigned i; + NSUserDefaults *defs; + NSMutableArray *files = nil; // Files to parse + NSString *templateFileName = nil; // makeIndex template file name + NSMutableDictionary *infoDictionary = nil; // user info + NSDictionary *variablesDictionary = nil; // variables dictionary + BOOL goOn = YES; + BOOL splitByEntities = NO; + NSFileManager *fileManager = nil; + NSString *documentationDirectory = nil; + NSString *declared = nil; + NSString *project = nil; + BOOL generateHtml = YES; + BOOL ignoreDependencies = NO; + BOOL showDependencies = NO; + id obj = nil; + + CREATE_AUTORELEASE_POOL(pool); + +#ifdef GS_PASS_ARGUMENTS + [NSProcessInfo initializeWithArguments: argv count: argc environment: env]; +#endif + + defs = [NSUserDefaults standardUserDefaults]; + [defs registerDefaults: [NSDictionary dictionaryWithObjectsAndKeys: + @"Untitled", @"Project", + nil]]; + + verbose = [defs boolForKey: @"Verbose"]; + ignoreDependencies = [defs boolForKey: @"IgnoreDependencies"]; + showDependencies = [defs boolForKey: @"ShowDependencies"]; + + if (ignoreDependencies == YES) + { + if (showDependencies == YES) + { + showDependencies = NO; + NSLog(@"ShowDependencies(YES) used with IgnoreDependencies(YES)"); + } + } + + obj = [defs objectForKey: @"GenerateHtml"]; + if (obj != nil) + { + generateHtml = [defs boolForKey: @"GenerateHtml"]; + } + + declared = [defs stringForKey: @"Declared"]; + project = [defs stringForKey: @"Project"]; + + documentationDirectory = [defs stringForKey: @"DocumentationDirectory"]; + if (documentationDirectory == nil) + { + documentationDirectory = @""; + } + + proc = [NSProcessInfo processInfo]; + if (proc == nil) + { + NSLog(@"unable to get process information!"); + goOn = NO; + } + + fileManager = [NSFileManager defaultManager]; + if (goOn) + { + args = [proc arguments]; + + // First, process arguments + for (i = 1; goOn && i < [args count]; i++) + { + NSString *arg = [args objectAtIndex: i]; + + // is this an option ? + if ([arg hasPrefix: @"--"]) + { + NSString *argWithoutPrefix = [arg stringByDeletingPrefix: @"--"]; + NSString *key = nil; + NSString *value = nil; + NSArray *parts = [argWithoutPrefix componentsSeparatedByString: + @"="]; + + key = [parts objectAtIndex: 0]; + + if ([parts count] > 1) + value = [[parts subarrayWithRange: + NSMakeRange(1, [parts count] - 1)] + componentsJoinedByString: @"="]; + + // projectName option + if ([key isEqualToString: @"projectName"] + || [key isEqualToString: @"project"]) + { + project = value; + NSCAssert([project length], @"No project name"); + } + // template option + else if ([key isEqualToString: @"template"]) + { + templateFileName = value; + NSCAssert([templateFileName length], @"No template filename"); + } + else if ([key isEqualToString: @"splitByEntities"]) + { + splitByEntities = [value boolValue]; + } + // Verbose + else if ([key hasPrefix: @"verbose"]) + { + NSCAssert1(value, @"No value for %@", key); + + verbose = [value intValue]; + + if (verbose > 0) + { + NSMutableSet *debugSet = [proc debugSet]; + [debugSet addObject: @"dflt"]; + } + } + // define option + else if ([key hasPrefix: @"define-"]) + { + if (!infoDictionary) + infoDictionary = [NSMutableDictionary dictionary]; + + NSCAssert1(value, @"No value for %@", key); + + [infoDictionary setObject: value + forKey: + [key stringByDeletingPrefix: @"define-"]]; + } + // DocumentationDirectory + else if ([key hasPrefix: @"documentationDirectory"]) + { + if (!value) + value = @""; + + documentationDirectory = value; + } +/* // unknown option + else + { + NSLog(@"Unknown option %@", arg); + goOn = NO; + };*/ + } + // file to parse + else + { + if (!files) + files = [NSMutableArray array]; + + [files addObject: arg]; + } + } + } + + //Default Values + if (goOn) + { + if (!project) + project = @"unknown"; + } + + // Verify option compatibilities + if (goOn) + { + } + + //Variables + if (goOn) + { + NSMutableDictionary *variablesMutableDictionary = + [NSMutableDictionary dictionary]; + NSEnumerator *enumer = [infoDictionary keyEnumerator]; + id key; + + while ((key = [enumer nextObject])) + { + id value = [infoDictionary objectForKey: key]; + + [variablesMutableDictionary + setObject: value + forKey: [NSString stringWithFormat: @"[[infoDictionary.%@]]", key]]; + } + + [variablesMutableDictionary setObject: [NSCalendarDate calendarDate] + forKey: @"[[timestampString]]"]; + + if (project) + [variablesMutableDictionary setObject: project + forKey: @"[[projectName]]"]; + + variablesDictionary = [[variablesMutableDictionary copy] autorelease]; + + if (verbose >= 3) + { + NSEnumerator *enumer = [variablesDictionary keyEnumerator]; + id key; + + while ((key = [enumer nextObject])) + { + NSLog(@"Variables: %@=%@", + key, + [variablesDictionary objectForKey: key]); + } + } + } + + // Find Files to parse + if (goOn) + { + if ([files count] < 1) + { + NSLog(@"No file names given to parse."); + goOn = NO; + } + else + { +/* NSMutableArray* tmpNewFiles=[NSMutableArray array]; + for (i=0;goOn && i<[files count];i++) + { + NSString* file = [files objectAtIndex: i]; + BOOL isDirectory=NO; + if (![fileManager fileExistsAtPath:file isDirectory:&isDirectory]) + { + NSLog(@"File %@ doesn't exist",file); + goOn=NO; + } + else + { + if (isDirectory) + { + NSArray* tmpFiles=FilesInPathWithExtension(file,PathExtension_EOModel); + [tmpNewFiles addObjectsFromArray:tmpFiles]; + tmpFiles=FilesInPathWithExtension(file,PathExtension_Model); + [tmpNewFiles addObjectsFromArray:tmpFiles]; + } + else + { + [tmpNewFiles addObject:file]; + } + } + } + files=tmpNewFiles; + files=(NSMutableArray*)[files sortedArrayUsingSelector:@selector(compare:)]; + NSDebugLog(@"files=%@",files); +*/ + } + } + + if (goOn) + { + NSString *textTemplate = [NSString stringWithContentsOfFile: + templateFileName]; + + for (i = 0; goOn && i < [files count]; i++) + { + int xmlId = 0; + NSString *file = [files objectAtIndex: i]; + NSAutoreleasePool *arp = [NSAutoreleasePool new]; + + if (verbose >= 1) + { + NSLog(@"File %d/%d - Processing %@", + (i+1), + [files count], + file); + } + NS_DURING + { + EOModel *model; + +// model=[[[EOModel alloc]autorelease]initWithContentsOfFile:file]; + model = [[[EOModel alloc] initWithContentsOfFile: file] + autorelease]; + + if (model) + { + NSString *gsdocModelContent = nil; + NSString *gsdocEntitiesContent = nil; + NSDictionary *entities = nil; + + NSLog(@"Model %@ loaded", file); + + gsdocModelContent = [model gsdocContentSplittedByEntities: + (splitByEntities + ? &entities : NULL) + withIdPtr: NULL/*&xmlId*/];//Debugging + + if (gsdocModelContent == nil) + { + NSLog(@"File %d/%d - Error generating doc for %@", + (i+1), + [files count], + file); + goOn = NO; + } + else + { + int iGenerateDoc = 0; + int iGenerateCount = 0; + NSString *fileContent = nil; + NSString *baseFileName = nil; + NSString *fileName = nil; + NSMutableDictionary *variablesMutableDictionary = nil; + NSArray *entitiesNames = [[entities allKeys] + sortedArrayUsingSelector: + @selector(compare:)]; + NSMutableString *entitiesIndex = [NSMutableString + stringWithString: + @"\n"]; + + iGenerateCount = [entitiesNames count] + 1; + variablesMutableDictionary = [variablesDictionary + mutableCopy]; + + for (iGenerateDoc = 0; + iGenerateDoc < iGenerateCount; + iGenerateDoc++) + { + NSString *theFile = nil; + NSString *content = nil; + + if (iGenerateDoc == (iGenerateCount - 1)) + { + NSMutableDictionary *tmpVariablesMutableDictionary = nil; + + theFile = file; + [entitiesIndex appendString: @"\n"]; + tmpVariablesMutableDictionary = + [NSMutableDictionary dictionaryWithObjectsAndKeys: + entitiesIndex, + @"[[entities]]", + nil]; + content = TextByReplacingVariablesInText(gsdocModelContent, tmpVariablesMutableDictionary); + } + else + { + NSString *entityName = [entitiesNames + objectAtIndex: + iGenerateDoc]; + + theFile = [NSString stringWithFormat: @"%@+%@", + [file stringByDeletingPathExtension], + entityName]; + content = [entities objectForKey: entityName]; + [entitiesIndex appendFormat: + @"%@\n", + theFile, + entityName]; + } + + baseFileName = [theFile + stringByDeletingPathExtension]; + fileName = [baseFileName + stringByAppendingPathExtension: PathExtension_GSDoc]; + fileName = [documentationDirectory stringByAppendingPathComponent: fileName]; + + [variablesMutableDictionary setObject: fileName + forKey: @"[[fileName]]"]; + [variablesMutableDictionary setObject: baseFileName + forKey: + @"[[baseFileName]]"]; + [variablesMutableDictionary setObject: content + forKey: @"[[content]]"]; + + fileContent = TextByReplacingVariablesInText(textTemplate, variablesMutableDictionary); + [fileContent writeToFile: fileName + atomically: NO]; + } + + if (verbose >= 1) + { + NSLog(@"File %d/%d - Generating %@ - OK", + (i+1), + [files count], + file); + } + } + } + else + { + NSLog(@"File %d/%d - Error parsing '%@'", + (i+1), + [files count], + file); + goOn = NO; + } + } + NS_HANDLER + { + NSLog(@"File %d/%d - Parsing '%@' - %@", + (i+1), + [files count], + file, + [localException reason]); + goOn = NO; + } + NS_ENDHANDLER; + + DESTROY(arp); + } + } + + [pool release]; + + return (goOn ? 0 : 1); +} diff --git a/Version b/Version new file mode 100644 index 0000000..a3384f9 --- /dev/null +++ b/Version @@ -0,0 +1,17 @@ +# This file is included in various Makefile's to get version information. +# Compatible with Bourne shell syntax, so it can included there too. + +# The gcc version required to compile the library. +GNUSTEP_GCC=2.95.2 + +# The version number of this release. +MAJOR_VERSION=0 +MINOR_VERSION=9 +SUBMINOR_VERSION=0 +GDL_VERSION=${MAJOR_VERSION}.${MINOR_VERSION}.${SUBMINOR_VERSION} +VERSION=${GDL_VERSION} + +GDL_FTP_MACHINE=ftp.gnustep.org +GDL_FTP_DIRECTORY=pub/gnustep/gdl2 +GDL_SNAP_FTP_MACHINE=ftp.gnustep.org +GDL_SNAP_FTP_DIRECTORY=pub/daily-snapshots diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..031d25d --- /dev/null +++ b/config.h.in @@ -0,0 +1,35 @@ +/* + config.h.in + + Copyright (C) 2002 Free Software Foundation, Inc. + + Author: Mirko Viviani + Date: September 2002 + + This file is part of the GNUstep Database Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __config_h__ +#define __config_h__ + + +/* Define if Foundation implements KeyValueCoding. */ +#define FOUNDATION_HAS_KVC 1 + + +#endif /* __config_h__ */ diff --git a/config/postgres.m4 b/config/postgres.m4 new file mode 100644 index 0000000..3dae84b --- /dev/null +++ b/config/postgres.m4 @@ -0,0 +1,56 @@ +dnl AM_PATH_PGSQL([, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +AC_DEFUN(AM_PATH_PGSQL,[ +AC_ARG_WITH(pgsql-include, + [ --with-pgsql-include=PATH include path for postgres headers], + pgsql_incdir="$withval", pgsql_incdir="no") + +AC_ARG_WITH(pgsql-library, + [ --with-pgsql-library=PATH library path for pgsql libraries], + pgsql_libdir="$withval", pgsql_libdir="no") + + cppflags_temp="$CPPFLAGS" + libs_temp=$LIBS + + CPPFLAGS="$CPPFLAGS -I/usr/local/pgsql/include" + LIBS="$LIBS -L/usr/local/pgsql/lib" + + if test "$pgsql_incdir" != "no"; then + CPPFLAGS="$CPPFLAGS -I$pgsql_incdir" + fi + if test "$pgsql_libdir" != "no"; then + LIBS="$LIBS -L$pgsql_libdir" + fi + + POSTGRES_DATABASE="no" + + AC_MSG_CHECKING(for PostgreSQL database) + + AC_CHECK_HEADERS(libpq-fe.h) + if test $ac_cv_header_libpq_fe_h = yes; then + AC_CHECK_LIB(pq, main, pgsql_ok=yes, pgsql_ok=no) + + if test "$pgsql_ok" = yes; then + POSTGRES_INCLUDES="$CPPFLAGS" + POSTGRES_LIB_DIRS="$LIBS" + POSTGRES_LIBS="-lpq" + POSTGRES_DATABASE="yes" + + AC_MSG_RESULT(yes) + ifelse([$1], , :, [$1]) + fi + fi + + if test $POSTGRES_DATABASE = no; then + AC_MSG_RESULT(no) + ifelse([$2], , :, [$2]) + fi + + CPPFLAGS="$cppflags_temp" + LIBS="$libs_temp" + + AC_SUBST(POSTGRES_DATABASE) + AC_SUBST(POSTGRES_INCLUDES) + AC_SUBST(POSTGRES_LIB_DIRS) + AC_SUBST(POSTGRES_LIBS) +]) + diff --git a/configure b/configure new file mode 100755 index 0000000..28e212b --- /dev/null +++ b/configure @@ -0,0 +1,3636 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.53. +# +# Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + + +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi + +# NLS nuisances. +# Support unset when possible. +if (FOO=FOO; unset FOO) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + +(set +x; test -n "`(LANG=C; export LANG) 2>&1`") && + { $as_unset LANG || test "${LANG+set}" != set; } || + { LANG=C; export LANG; } +(set +x; test -n "`(LC_ALL=C; export LC_ALL) 2>&1`") && + { $as_unset LC_ALL || test "${LC_ALL+set}" != set; } || + { LC_ALL=C; export LC_ALL; } +(set +x; test -n "`(LC_TIME=C; export LC_TIME) 2>&1`") && + { $as_unset LC_TIME || test "${LC_TIME+set}" != set; } || + { LC_TIME=C; export LC_TIME; } +(set +x; test -n "`(LC_CTYPE=C; export LC_CTYPE) 2>&1`") && + { $as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set; } || + { LC_CTYPE=C; export LC_CTYPE; } +(set +x; test -n "`(LANGUAGE=C; export LANGUAGE) 2>&1`") && + { $as_unset LANGUAGE || test "${LANGUAGE+set}" != set; } || + { LANGUAGE=C; export LANGUAGE; } +(set +x; test -n "`(LC_COLLATE=C; export LC_COLLATE) 2>&1`") && + { $as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set; } || + { LC_COLLATE=C; export LC_COLLATE; } +(set +x; test -n "`(LC_NUMERIC=C; export LC_NUMERIC) 2>&1`") && + { $as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set; } || + { LC_NUMERIC=C; export LC_NUMERIC; } +(set +x; test -n "`(LC_MESSAGES=C; export LC_MESSAGES) 2>&1`") && + { $as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set; } || + { LC_MESSAGES=C; export LC_MESSAGES; } + + +# Name of the executable. +as_me=`(basename "$0") 2>/dev/null || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conftest.sh + echo "exit 0" >>conftest.sh + chmod +x conftest.sh + if (PATH=".;."; conftest.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conftest.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=$PATH_SEPARATOR; export CDPATH; } + + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +exec 6>&1 + +# +# Initializations. +# +ac_default_prefix=/usr/local +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Maximum number of lines to put in a shell here document. +# This variable seems obsolete. It should probably be removed, and +# only ac_max_sed_lines should be used. +: ${ac_max_here_lines=38} + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= + +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_STAT_H +# include +#endif +#if STDC_HEADERS +# include +# include +#else +# if HAVE_STDLIB_H +# include +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_INTTYPES_H +# include +#else +# if HAVE_STDINT_H +# include +# endif +#endif +#if HAVE_UNISTD_H +# include +#endif" + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +ac_prev= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval "enable_$ac_feature=no" ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "enable_$ac_feature='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "with_$ac_package='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/-/_/g'` + eval "with_$ac_package=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# Be sure to have absolute paths. +for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ + localstatedir libdir includedir oldincludedir infodir mandir +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_confdir=`(dirname "$0") 2>/dev/null || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias +ac_env_CC_set=${CC+set} +ac_env_CC_value=$CC +ac_cv_env_CC_set=${CC+set} +ac_cv_env_CC_value=$CC +ac_env_CFLAGS_set=${CFLAGS+set} +ac_env_CFLAGS_value=$CFLAGS +ac_cv_env_CFLAGS_set=${CFLAGS+set} +ac_cv_env_CFLAGS_value=$CFLAGS +ac_env_LDFLAGS_set=${LDFLAGS+set} +ac_env_LDFLAGS_value=$LDFLAGS +ac_cv_env_LDFLAGS_set=${LDFLAGS+set} +ac_cv_env_LDFLAGS_value=$LDFLAGS +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +_ACEOF + + cat <<_ACEOF +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data [PREFIX/share] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --infodir=DIR info documentation [PREFIX/info] + --mandir=DIR man documentation [PREFIX/man] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-pgsql-include=PATH include path for postgres headers + --with-pgsql-library=PATH library path for pgsql libraries + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have + headers in a nonstandard directory + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +_ACEOF +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d $ac_dir || continue + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac +# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be +# absolute. +ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd` +ac_abs_top_builddir=`cd "$ac_dir" && cd $ac_top_builddir && pwd` +ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd` +ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd` + + cd $ac_dir + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_srcdir/configure.gnu; then + echo + $SHELL $ac_srcdir/configure.gnu --help=recursive + elif test -f $ac_srcdir/configure; then + echo + $SHELL $ac_srcdir/configure --help=recursive + elif test -f $ac_srcdir/configure.ac || + test -f $ac_srcdir/configure.in; then + echo + $ac_configure --help + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi + cd $ac_popdir + done +fi + +test -n "$ac_init_help" && exit 0 +if $ac_init_version; then + cat <<\_ACEOF + +Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 +Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit 0 +fi +exec 5>config.log +cat >&5 <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.53. Invocation command line was + + $ $0 $@ + +_ACEOF +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +hostinfo = `(hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell meta-characters. +ac_configure_args= +ac_sep= +for ac_arg +do + case $ac_arg in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n ) continue ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + continue ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + ac_sep=" " ;; + esac + # Get rid of the leading space. +done + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Be sure not to use single quotes in there, as some shells, +# such as our DU 5.0 friend, will then `close' the trap. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +{ + (set) 2>&1 | + case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in + *ac_space=\ *) + sed -n \ + "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" + ;; + *) + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} + echo + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + sed "/^$/d" confdefs.h + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core core.* *.core && + rm -rf conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status + ' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo >confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in `(set) 2>&1 | + sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val="\$ac_cv_env_${ac_var}_value" + eval ac_new_val="\$ac_env_${ac_var}_value" + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + + + + + + +if test -z "$GNUSTEP_SYSTEM_ROOT"; then + { { echo "$as_me:$LINENO: error: You must run the GNUstep initialization script first!" >&5 +echo "$as_me: error: You must run the GNUstep initialization script first!" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_config_headers="$ac_config_headers config.h" + + + +#-------------------------------------------------------------------- +# Check for Postgres database +#-------------------------------------------------------------------- + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$as_dir/$ac_word" ${1+"$@"} + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH" >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH" >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +echo "$as_me:$LINENO: checking for C compiler default output" >&5 +echo $ECHO_N "checking for C compiler default output... $ECHO_C" >&6 +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 + (eval $ac_link_default) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Find the output, starting from the most likely. This scheme is +# not robust to junk in `.', hence go to wildcards (a.*) only as a last +# resort. + +# Be careful to initialize this variable, since it used to be cached. +# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. +ac_cv_exeext= +for ac_file in `ls a_out.exe a.exe conftest.exe 2>/dev/null; + ls a.out conftest 2>/dev/null; + ls a.* conftest.* 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb | *.xSYM ) ;; + a.out ) # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool --akim. + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables" >&5 +echo "$as_me: error: C compiler cannot create executables" >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6 + +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +rm -f a.out a.exe conftest$ac_cv_exeext +ac_clean_files=$ac_clean_files_save +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6 + +echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in `(ls conftest.exe; ls conftest; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link" >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link" >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6 + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile" >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile" >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6 +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_compiler_gnu=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_prog_cc_g=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +#ifndef __cplusplus + choke me +#endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + ''\ + '#include ' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include +$ac_declaration +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +continue +fi +rm -f conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +$ac_declaration +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +fi +rm -f conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +fi +rm -f conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6 +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check" >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include +#include +#include +#include + +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_header_stdc=no +fi +rm -f conftest.err conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core core.* *.core conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +eval "$as_ac_Header=no" +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + +# Check whether --with-pgsql-include or --without-pgsql-include was given. +if test "${with_pgsql_include+set}" = set; then + withval="$with_pgsql_include" + pgsql_incdir="$withval" +else + pgsql_incdir="no" +fi; + + +# Check whether --with-pgsql-library or --without-pgsql-library was given. +if test "${with_pgsql_library+set}" = set; then + withval="$with_pgsql_library" + pgsql_libdir="$withval" +else + pgsql_libdir="no" +fi; + + cppflags_temp="$CPPFLAGS" + libs_temp=$LIBS + + CPPFLAGS="$CPPFLAGS -I/usr/local/pgsql/include" + LIBS="$LIBS -L/usr/local/pgsql/lib" + + if test "$pgsql_incdir" != "no"; then + CPPFLAGS="$CPPFLAGS -I$pgsql_incdir" + fi + if test "$pgsql_libdir" != "no"; then + LIBS="$LIBS -L$pgsql_libdir" + fi + + POSTGRES_DATABASE="no" + + echo "$as_me:$LINENO: checking for PostgreSQL database" >&5 +echo $ECHO_N "checking for PostgreSQL database... $ECHO_C" >&6 + + +for ac_header in libpq-fe.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_header_compiler=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc in + yes:no ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};; + no:yes ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + if test $ac_cv_header_libpq_fe_h = yes; then + echo "$as_me:$LINENO: checking for main in -lpq" >&5 +echo $ECHO_N "checking for main in -lpq... $ECHO_C" >&6 +if test "${ac_cv_lib_pq_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpq $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_pq_main=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_pq_main=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_pq_main" >&5 +echo "${ECHO_T}$ac_cv_lib_pq_main" >&6 +if test $ac_cv_lib_pq_main = yes; then + pgsql_ok=yes +else + pgsql_ok=no +fi + + + if test "$pgsql_ok" = yes; then + POSTGRES_INCLUDES="$CPPFLAGS" + POSTGRES_LIB_DIRS="$LIBS" + POSTGRES_LIBS="-lpq" + POSTGRES_DATABASE="yes" + + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + enable_pgsql=yes + fi + fi + + if test $POSTGRES_DATABASE = no; then + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + enable_pgsql=no + fi + + CPPFLAGS="$cppflags_temp" + LIBS="$libs_temp" + + + + + + +if test $enable_pgsql = yes; then + EOADAPTORS="$EOADAPTORS Postgres95" + + HAVE_PGSQL=1 +# AC_DEFINE(HAVE_LIBXML,1, +# [Define if libxml available]) +else + HAVE_PGSQL=0 +fi + + + + +#-------------------------------------------------------------------- +# Record the version +#-------------------------------------------------------------------- +echo "$as_me:$LINENO: checking for the version of GDL2 we are compiling" >&5 +echo $ECHO_N "checking for the version of GDL2 we are compiling... $ECHO_C" >&6 +if test -f "Version"; then + . ./Version +fi +echo "$as_me:$LINENO: result: $VERSION" >&5 +echo "${ECHO_T}$VERSION" >&6 + + + + + + +#-------------------------------------------------------------------- +# Write the Makefiles +#-------------------------------------------------------------------- +ac_config_files="$ac_config_files gdl2.make EOAdaptors/GNUmakefile EOAdaptors/Postgres95/GNUmakefile EOAdaptors/Postgres95/Makefile.preamble" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overriden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if cmp -s $cache_file confcache; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +}' +fi + +DEFS=-DHAVE_CONFIG_H + + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi + +# NLS nuisances. +# Support unset when possible. +if (FOO=FOO; unset FOO) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + +(set +x; test -n "`(LANG=C; export LANG) 2>&1`") && + { $as_unset LANG || test "${LANG+set}" != set; } || + { LANG=C; export LANG; } +(set +x; test -n "`(LC_ALL=C; export LC_ALL) 2>&1`") && + { $as_unset LC_ALL || test "${LC_ALL+set}" != set; } || + { LC_ALL=C; export LC_ALL; } +(set +x; test -n "`(LC_TIME=C; export LC_TIME) 2>&1`") && + { $as_unset LC_TIME || test "${LC_TIME+set}" != set; } || + { LC_TIME=C; export LC_TIME; } +(set +x; test -n "`(LC_CTYPE=C; export LC_CTYPE) 2>&1`") && + { $as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set; } || + { LC_CTYPE=C; export LC_CTYPE; } +(set +x; test -n "`(LANGUAGE=C; export LANGUAGE) 2>&1`") && + { $as_unset LANGUAGE || test "${LANGUAGE+set}" != set; } || + { LANGUAGE=C; export LANGUAGE; } +(set +x; test -n "`(LC_COLLATE=C; export LC_COLLATE) 2>&1`") && + { $as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set; } || + { LC_COLLATE=C; export LC_COLLATE; } +(set +x; test -n "`(LC_NUMERIC=C; export LC_NUMERIC) 2>&1`") && + { $as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set; } || + { LC_NUMERIC=C; export LC_NUMERIC; } +(set +x; test -n "`(LC_MESSAGES=C; export LC_MESSAGES) 2>&1`") && + { $as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set; } || + { LC_MESSAGES=C; export LC_MESSAGES; } + + +# Name of the executable. +as_me=`(basename "$0") 2>/dev/null || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conftest.sh + echo "exit 0" >>conftest.sh + chmod +x conftest.sh + if (PATH=".;."; conftest.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conftest.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 +echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 +echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=$PATH_SEPARATOR; export CDPATH; } + +exec 6>&1 + +# Open the log real soon, to keep \$[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. Logging --version etc. is OK. +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX +} >&5 +cat >&5 <<_CSEOF + +This file was extended by $as_me, which was +generated by GNU Autoconf 2.53. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +_CSEOF +echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 +echo >&5 +_ACEOF + +# Files that config.status was made for. +if test -n "$ac_config_files"; then + echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_headers"; then + echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_links"; then + echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_commands"; then + echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS +fi + +cat >>$CONFIG_STATUS <<\_ACEOF + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to ." +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.53, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." +srcdir=$srcdir +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "x$1" : 'x\([^=]*\)='` + ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + shift + set dummy "$ac_option" "$ac_optarg" ${1+"$@"} + shift + ;; + -*);; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_need_defaults=false;; + esac + + case $1 in + # Handling of the options. +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running $SHELL $0 " $ac_configure_args " --no-create --no-recursion" + exec $SHELL $0 $ac_configure_args --no-create --no-recursion ;; +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:$LINENO: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + shift + CONFIG_FILES="$CONFIG_FILES $1" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + shift + CONFIG_HEADERS="$CONFIG_HEADERS $1" + ac_need_defaults=false;; + + # This is an error. + -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + esac + shift +done + +_ACEOF + + + + + +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "gdl2.make" ) CONFIG_FILES="$CONFIG_FILES gdl2.make" ;; + "EOAdaptors/GNUmakefile" ) CONFIG_FILES="$CONFIG_FILES EOAdaptors/GNUmakefile" ;; + "EOAdaptors/Postgres95/GNUmakefile" ) CONFIG_FILES="$CONFIG_FILES EOAdaptors/Postgres95/GNUmakefile" ;; + "EOAdaptors/Postgres95/Makefile.preamble" ) CONFIG_FILES="$CONFIG_FILES EOAdaptors/Postgres95/Makefile.preamble" ;; + "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. +: ${TMPDIR=/tmp} +{ + tmp=`(umask 077 && mktemp -d -q "$TMPDIR/csXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=$TMPDIR/cs$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in $TMPDIR" >&2 + { (exit 1); exit 1; } +} + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF + +# +# CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "\$CONFIG_FILES"; then + # Protect against being on the right side of a sed subst in config.status. + sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; + s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF +s,@SHELL@,$SHELL,;t t +s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t +s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t +s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t +s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t +s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t +s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t +s,@exec_prefix@,$exec_prefix,;t t +s,@prefix@,$prefix,;t t +s,@program_transform_name@,$program_transform_name,;t t +s,@bindir@,$bindir,;t t +s,@sbindir@,$sbindir,;t t +s,@libexecdir@,$libexecdir,;t t +s,@datadir@,$datadir,;t t +s,@sysconfdir@,$sysconfdir,;t t +s,@sharedstatedir@,$sharedstatedir,;t t +s,@localstatedir@,$localstatedir,;t t +s,@libdir@,$libdir,;t t +s,@includedir@,$includedir,;t t +s,@oldincludedir@,$oldincludedir,;t t +s,@infodir@,$infodir,;t t +s,@mandir@,$mandir,;t t +s,@build_alias@,$build_alias,;t t +s,@host_alias@,$host_alias,;t t +s,@target_alias@,$target_alias,;t t +s,@DEFS@,$DEFS,;t t +s,@ECHO_C@,$ECHO_C,;t t +s,@ECHO_N@,$ECHO_N,;t t +s,@ECHO_T@,$ECHO_T,;t t +s,@LIBS@,$LIBS,;t t +s,@CC@,$CC,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@LDFLAGS@,$LDFLAGS,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t +s,@CPP@,$CPP,;t t +s,@POSTGRES_DATABASE@,$POSTGRES_DATABASE,;t t +s,@POSTGRES_INCLUDES@,$POSTGRES_INCLUDES,;t t +s,@POSTGRES_LIB_DIRS@,$POSTGRES_LIB_DIRS,;t t +s,@POSTGRES_LIBS@,$POSTGRES_LIBS,;t t +s,@EOADAPTORS@,$EOADAPTORS,;t t +s,@VERSION@,$VERSION,;t t +s,@MAJOR_VERSION@,$MAJOR_VERSION,;t t +s,@MINOR_VERSION@,$MINOR_VERSION,;t t +s,@SUBMINOR_VERSION@,$SUBMINOR_VERSION,;t t +s,@GCC_VERSION@,$GCC_VERSION,;t t +CEOF + +_ACEOF + + cat >>$CONFIG_STATUS <<\_ACEOF + # Split the substitutions into bite-sized pieces for seds with + # small command number limits, like on Digital OSF/1 and HP-UX. + ac_max_sed_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # Line after last line for current file. + ac_more_lines=: + ac_sed_cmds= + while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { case "$ac_dir" in + [\\/]* | ?:[\\/]* ) as_incr_dir=;; + *) as_incr_dir=.;; +esac +as_dummy="$ac_dir" +for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do + case $as_mkdir_dir in + # Skip DOS drivespec + ?:) as_incr_dir=$as_mkdir_dir ;; + *) + as_incr_dir=$as_incr_dir/$as_mkdir_dir + test -d "$as_incr_dir" || + mkdir "$as_incr_dir" || + { { echo "$as_me:$LINENO: error: cannot create \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; } + ;; + esac +done; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac +# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be +# absolute. +ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd` +ac_abs_top_builddir=`cd "$ac_dir" && cd $ac_top_builddir && pwd` +ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd` +ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd` + + + + if test x"$ac_file" != x-; then + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + configure_input= + else + configure_input="$ac_file. " + fi + configure_input=$configure_input"Generated from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo $f;; + *) # Relative + if test -f "$f"; then + # Build tree + echo $f + elif test -f "$srcdir/$f"; then + # Source tree + echo $srcdir/$f + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;t t +s,@srcdir@,$ac_srcdir,;t t +s,@abs_srcdir@,$ac_abs_srcdir,;t t +s,@top_srcdir@,$ac_top_srcdir,;t t +s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t +s,@builddir@,$ac_builddir,;t t +s,@abs_builddir@,$ac_abs_builddir,;t t +s,@top_builddir@,$ac_top_builddir,;t t +s,@abs_top_builddir@,$ac_abs_top_builddir,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_HEADER section. +# + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='[ ].*$,\1#\2' +ac_dC=' ' +ac_dD=',;t' +# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='$,\1#\2define\3' +ac_uC=' ' +ac_uD=',;t' + +for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo $f;; + *) # Relative + if test -f "$f"; then + # Build tree + echo $f + elif test -f "$srcdir/$f"; then + # Source tree + echo $srcdir/$f + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + # Remove the trailing spaces. + sed 's/[ ]*$//' $ac_file_inputs >$tmp/in + +_ACEOF + +# Transform confdefs.h into two sed scripts, `conftest.defines' and +# `conftest.undefs', that substitutes the proper values into +# config.h.in to produce config.h. The first handles `#define' +# templates, and the second `#undef' templates. +# And first: Protect against being on the right side of a sed subst in +# config.status. Protect against being in an unquoted here document +# in config.status. +rm -f conftest.defines conftest.undefs +# Using a here document instead of a string reduces the quoting nightmare. +# Putting comments in sed scripts is not portable. +# +# `end' is used to avoid that the second main sed command (meant for +# 0-ary CPP macros) applies to n-ary macro definitions. +# See the Autoconf documentation for `clear'. +cat >confdef2sed.sed <<\_ACEOF +s/[\\&,]/\\&/g +s,[\\$`],\\&,g +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp +t end +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp +: end +_ACEOF +# If some macros were called several times there might be several times +# the same #defines, which is useless. Nevertheless, we may not want to +# sort them, since we want the *last* AC-DEFINE to be honored. +uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines +sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs +rm -f confdef2sed.sed + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >>conftest.undefs <<\_ACEOF +s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, +_ACEOF + +# Break up conftest.defines because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS +echo ' if egrep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS +echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS +echo ' :' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.defines >/dev/null +do + # Write a limited-size here document to $tmp/defines.sed. + echo ' cat >$tmp/defines.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#define' lines. + echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/defines.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines +echo ' fi # egrep' >>$CONFIG_STATUS +echo >>$CONFIG_STATUS + +# Break up conftest.undefs because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #undef templates' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.undefs >/dev/null +do + # Write a limited-size here document to $tmp/undefs.sed. + echo ' cat >$tmp/undefs.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#undef' + echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/undefs.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail + rm -f conftest.undefs + mv conftest.tail conftest.undefs +done +rm -f conftest.undefs + +cat >>$CONFIG_STATUS <<\_ACEOF + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + echo "/* Generated by configure. */" >$tmp/config.h + else + echo "/* $ac_file. Generated by configure. */" >$tmp/config.h + fi + cat $tmp/in >>$tmp/config.h + rm -f $tmp/in + if test x"$ac_file" != x-; then + if cmp -s $ac_file $tmp/config.h 2>/dev/null; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { case "$ac_dir" in + [\\/]* | ?:[\\/]* ) as_incr_dir=;; + *) as_incr_dir=.;; +esac +as_dummy="$ac_dir" +for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do + case $as_mkdir_dir in + # Skip DOS drivespec + ?:) as_incr_dir=$as_mkdir_dir ;; + *) + as_incr_dir=$as_incr_dir/$as_mkdir_dir + test -d "$as_incr_dir" || + mkdir "$as_incr_dir" || + { { echo "$as_me:$LINENO: error: cannot create \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; } + ;; + esac +done; } + + rm -f $ac_file + mv $tmp/config.h $ac_file + fi + else + cat $tmp/config.h + rm -f $tmp/config.h + fi +done +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + exec 5>/dev/null + $SHELL $CONFIG_STATUS || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..a0c9f0f --- /dev/null +++ b/configure.ac @@ -0,0 +1,71 @@ +# configure.in for GDL2 library +# Process this file with autoconf to produce a configure script. +# +# Copyright (C) 2002 Free Software Foundation, Inc. +# +# Written by: Mirko Viviani +# +# This file is part of the GDL2 library. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA + +builtin(include, config/postgres.m4)dnl + +AC_INIT + +if test -z "$GNUSTEP_SYSTEM_ROOT"; then + AC_MSG_ERROR([You must run the GNUstep initialization script first!]) +fi + +AC_CONFIG_HEADER(config.h) + + +#-------------------------------------------------------------------- +# Check for Postgres database +#-------------------------------------------------------------------- + +AM_PATH_PGSQL(enable_pgsql=yes, enable_pgsql=no) +if test $enable_pgsql = yes; then + EOADAPTORS="$EOADAPTORS Postgres95" + + HAVE_PGSQL=1 +# AC_DEFINE(HAVE_LIBXML,1, +# [Define if libxml available]) +else + HAVE_PGSQL=0 +fi + + +AC_SUBST(EOADAPTORS) + +#-------------------------------------------------------------------- +# Record the version +#-------------------------------------------------------------------- +AC_MSG_CHECKING(for the version of GDL2 we are compiling) +if test -f "Version"; then + . ./Version +fi +AC_MSG_RESULT($VERSION) +AC_SUBST(VERSION) +AC_SUBST(MAJOR_VERSION) +AC_SUBST(MINOR_VERSION) +AC_SUBST(SUBMINOR_VERSION) +AC_SUBST(GCC_VERSION) + +#-------------------------------------------------------------------- +# Write the Makefiles +#-------------------------------------------------------------------- +AC_CONFIG_FILES([gdl2.make EOAdaptors/GNUmakefile EOAdaptors/Postgres95/GNUmakefile EOAdaptors/Postgres95/Makefile.preamble]) +AC_OUTPUT diff --git a/gdl2.make.in b/gdl2.make.in new file mode 100644 index 0000000..db8ef7a --- /dev/null +++ b/gdl2.make.in @@ -0,0 +1,49 @@ +# -*-makefile-*- +# gdl2.make +# +# Makefile include segment which handles linking to the GNUstep +# Database Library; requires the GNUstep makefile package. +# +# Copyright (C) 2002 Free Software Foundation, Inc. +# +# Author: Mirko Viviani +# +# This file is part of the GNUstep Database Library. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +# Don't reload if already loaded +ifneq ($(GDL2_LOADED),yes) +GDL2_LOADED=yes + +GDL2_VERSION = @VERSION@ +GDL2_MAJOR_VERSION = @MAJOR_VERSION@ +GDL2_MINOR_VERSION = @MINOR_VERSION@ +GDL2_SUBMINOR_VERSION = @SUBMINOR_VERSION@ + + +# Nothing special just include the library +ifeq ($(debug), yes) + AUXILIARY_TOOL_LIBS += -lgnustep-db2_d -lgnustep-db2control_d +else + AUXILIARY_TOOL_LIBS += -lgnustep-db2 -lgnustep-db2control +endif + + +# We depend upon the Foundation Extensions Library +include $(GNUSTEP_MAKEFILES)/extensions.make + +endif