)]}'
{
  "log": [
    {
      "commit": "bd070b2c1576680eed6a8f8e3cfc3affc4526041",
      "tree": "59699d8124b5acd9f87e0512a30fe17dd2301b76",
      "parents": [
        "3f50f752544bdb1be0b3f8a4906e9a5ecd5f5ea8"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "13417392+rzo1@users.noreply.github.com",
        "time": "Thu Oct 29 02:27:37 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 29 08:27:37 2026 +0700"
      },
      "message": "[OPENJPA-3033] Store char fields as CHAR(1) on Derby, H2 and SQL Server (#245)\n\n* [OPENJPA-3033] Store char fields as CHAR(1) on Derby and SQL Server\n\nDerbyDictionary and SQLServerDictionary used the DBDictionary default\nStoreCharsAsNumbers\u003dtrue, so a char was written as its code point. On a\nCHAR(1) column such as the one in the Jakarta Persistence TCK schema, Derby\nfailed the insert with 22001 (\u002797\u0027 does not fit) and SQL Server failed to\nread \u0027*\u0027 as an INTEGER. Both now default to native CHAR storage, like DB2,\nMySQL and PostgreSQL 9+; an explicit StoreCharsAsNumbers\u003dtrue still selects\nnumeric columns.\n\nA generated CHAR column for a char/Character field without an explicit\nlength is now CHAR(1) instead of CHAR(CharacterColumnSize), which Derby\nrejected as CHAR(255).\n\n* [OPENJPA-3033] Store char fields as CHAR(1) on H2 too"
    },
    {
      "commit": "3f50f752544bdb1be0b3f8a4906e9a5ecd5f5ea8",
      "tree": "10dc557ebae0cde828448260d8eeb159732bf75b",
      "parents": [
        "221937e887b502b1d8d2b7facc90971dcf53f544"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "13417392+rzo1@users.noreply.github.com",
        "time": "Thu Oct 29 02:24:25 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 29 08:24:25 2026 +0700"
      },
      "message": "[OPENJPA-3045] Order the locked query in TestPessimisticLocks so the skipped row is fixed (#243)"
    },
    {
      "commit": "221937e887b502b1d8d2b7facc90971dcf53f544",
      "tree": "f9b9c0c733547893f86adb3c6ea3c901c8801410",
      "parents": [
        "424ae3dbe3dde4e02525ed3533350030dc0ad563"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "13417392+rzo1@users.noreply.github.com",
        "time": "Thu Oct 29 02:23:57 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 29 08:23:57 2026 +0700"
      },
      "message": "[OPENJPA-3036] Match the keys of a bulk update or delete in a derived table on MySQL (#242)\n\nMySQL rejects an UPDATE or DELETE whose WHERE clause has a subquery that\nreads the changed table (error 1093). When the bulk statement has a\nsubquery, collect the primary keys of the matching rows in a derived\ntable, which MySQL materializes before changing any row, so the subquery\nstill sees the state before the statement. The new dictionary property\nAllowsBulkTargetInSubselect turns this on; it is false for MySQL."
    },
    {
      "commit": "424ae3dbe3dde4e02525ed3533350030dc0ad563",
      "tree": "9d6c7e12da33dc28be6dfb95ce30639eb53c3270",
      "parents": [
        "4cb46d12e1647ca0c040e6a50deeff0225159f7f"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "13417392+rzo1@users.noreply.github.com",
        "time": "Thu Oct 29 02:23:16 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 29 08:23:16 2026 +0700"
      },
      "message": "[OPENJPA-3035] Apply numeric promotion to the result type of arithmetic expressions (#241)"
    },
    {
      "commit": "4cb46d12e1647ca0c040e6a50deeff0225159f7f",
      "tree": "96e92eb81ca16573f903b799d1e0920fb5e58018",
      "parents": [
        "3a027180e4b02625f97e7f439728bc2ed5d29c6f"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "13417392+rzo1@users.noreply.github.com",
        "time": "Thu Oct 29 02:22:17 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 29 08:22:17 2026 +0700"
      },
      "message": "[OPENJPA-3042] Evaluate EXTRACT in memory with the ISO week and every temporal type (#239)\n\n* [OPENJPA-3042] Evaluate EXTRACT in memory with the ISO week and the local date and time of each temporal type\n\nWEEK was mapped to ALIGNED_DAY_OF_WEEK_IN_YEAR, a day of the week, and is now\nthe ISO-8601 week of the week based year. A java.sql.Timestamp was read as an\nInstant, which has no calendar fields, and java.util.Date, Calendar and\nInstant were rejected; they are now read as a local date and time. SECOND\nkeeps the nanoseconds and EXTRACT of null is null.\n\n* [OPENJPA-3042] Evaluate EXTRACT(DATE/TIME) in memory for every temporal type and render WEEK as ISO_WEEK on H2\n\n* [OPENJPA-3042] Use pattern matching in toTemporal"
    },
    {
      "commit": "3a027180e4b02625f97e7f439728bc2ed5d29c6f",
      "tree": "3189a4b1ce5cdc01b4921416148f41dbff359766",
      "parents": [
        "ead321648648cef2e314582112726ac7edc497fa"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "13417392+rzo1@users.noreply.github.com",
        "time": "Thu Oct 29 02:21:40 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 29 08:21:40 2026 +0700"
      },
      "message": "[OPENJPA-3040] Register criteria parameters used in the selection, group by and order by (#237)\n\n* [OPENJPA-3040] Register criteria parameters used in the selection, group by and order by\n\n* [OPENJPA-3040] Use try-with-resources in the test\n\n* [OPENJPA-3040] Use pattern matching and check the type of group by and order by expressions"
    },
    {
      "commit": "ead321648648cef2e314582112726ac7edc497fa",
      "tree": "6f3f71b28bd7811e32e59dd330149ee067c1fff4",
      "parents": [
        "cbac65e85fdfb655ccecc25492d17e83e368bfb0"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "13417392+rzo1@users.noreply.github.com",
        "time": "Thu Oct 29 02:20:51 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 29 08:20:51 2026 +0700"
      },
      "message": "[OPENJPA-3029][OPENJPA-3037] Fix EXTRACT on Derby and EXTRACT(WEEK) on MySQL and MariaDB (#236)\n\n* [OPENJPA-3029] Render EXTRACT on Derby with its per-field date and time functions\n\n* [OPENJPA-3037] Extract the ISO week on MySQL and MariaDB\n\n* [OPENJPA-3037] Extract the ISO week on H2 whatever the JVM locale\n\n* [OPENJPA-3029] Use try-with-resources in the test\n\n* [OPENJPA-3029] Use pattern matching for the cast of the extract operand"
    },
    {
      "commit": "cbac65e85fdfb655ccecc25492d17e83e368bfb0",
      "tree": "df02fbbc673893582d01724f75503114e3887767",
      "parents": [
        "c6f80d679ebcad54af317cb87165ca9496e81354"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "13417392+rzo1@users.noreply.github.com",
        "time": "Thu Oct 29 02:16:30 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 29 08:16:30 2026 +0700"
      },
      "message": "[OPENJPA-3027] Test each database against its oldest supported and newest LTS release (#234)"
    },
    {
      "commit": "c6f80d679ebcad54af317cb87165ca9496e81354",
      "tree": "0088e9e2fae0b88100128d7169c11d6a10eb560a",
      "parents": [
        "ab11a08b7b21220308422828faa895dea18950fb"
      ],
      "author": {
        "name": "Maxim Solodovnik",
        "email": "solomax666@gmail.com",
        "time": "Thu Oct 29 08:15:34 2026 +0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 29 08:15:34 2026 +0700"
      },
      "message": "[OPENJPA-2940] mssql is added to TCK script; run-build-matrix is improved (#233)\n\n* [OPENJPA-2940] mssql is added to TCK script; run-build-matrix is improved\n\n* [OPENJPA-2940] derby is added\n\n* [OPENJPA-2940] oracle is added to TCK\n\n* [OPENJPA-2940] comments are addressed"
    },
    {
      "commit": "ab11a08b7b21220308422828faa895dea18950fb",
      "tree": "471f4afeee7ef642c804d48b6c1c9a96410d43c4",
      "parents": [
        "cb575c6f2170c126993489f0a47c948074ec0d46",
        "e6eed60813b6be7a07f6a8f77cab5c1cf1098297"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Wed Oct 28 08:21:39 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 28 08:21:39 2026 -0300"
      },
      "message": "Merge pull request #235 from apache/OPENJPA-3030\n\n[OPENJPA-3030][OPENJPA-3031] Render LEFT, RIGHT and VARCHAR casts on Derby"
    },
    {
      "commit": "cb575c6f2170c126993489f0a47c948074ec0d46",
      "tree": "aaf144eae492b1038a18c9698b93a9907944fb16",
      "parents": [
        "434f89f833ce81f1328c59de2a5fe34334d9ef0b"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "13417392+rzo1@users.noreply.github.com",
        "time": "Wed Oct 28 02:37:21 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 28 08:37:21 2026 +0700"
      },
      "message": "[OPENJPA-3022] Do not cache a converted value whose element was changed in place (#229)"
    },
    {
      "commit": "434f89f833ce81f1328c59de2a5fe34334d9ef0b",
      "tree": "a2e20b4e8f7e7441353f9adb28cf66ee037aa40e",
      "parents": [
        "81823dd38f305241621e09fd01dab2dd72bf9141"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "13417392+rzo1@users.noreply.github.com",
        "time": "Wed Oct 28 02:27:08 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 28 08:27:08 2026 +0700"
      },
      "message": "[OPENJPA-3025] Keep orphan removal in an XML mapping that also cascades remove (#228)\n\n* [OPENJPA-3025] Keep orphan removal in an XML mapping that also cascades remove\n\nThe XML parser marked an orphan-removal relation dependent when the\none-to-one or one-to-many element started and applied the cascades when\nthe field ended, so a cascaded remove replaced the dependent marking and\nan element removed from the relation was not deleted. Apply orphan\nremoval after the cascades, as the annotation parser does.\n\n* [OPENJPA-3025] Use try-with-resources in the test"
    },
    {
      "commit": "81823dd38f305241621e09fd01dab2dd72bf9141",
      "tree": "edebd1fd71976eeb4f4f8c25bbb4f5d45ea90fb4",
      "parents": [
        "c158abf97c788c07fb5eaeca679750992aa4ba34"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "13417392+rzo1@users.noreply.github.com",
        "time": "Wed Oct 28 02:26:09 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 28 08:26:09 2026 +0700"
      },
      "message": "[OPENJPA-3021] Keep the value a converter returns instead of replacing it by a bean proxy (#227)\n\n* [OPENJPA-3021] Keep the value a converter returns instead of replacing it by a bean proxy\n\n* [OPENJPA-3021] Restore a converted value changed in place on rollback\n\n* [OPENJPA-3021] Add braces to single statement blocks\n\n* [OPENJPA-3021] Address review comments"
    },
    {
      "commit": "c158abf97c788c07fb5eaeca679750992aa4ba34",
      "tree": "e447b8250f69a3caf48bcda185719e7f599da24b",
      "parents": [
        "a2e9c6efe63eae61261bfaf159a53ee2ada0c192"
      ],
      "author": {
        "name": "Maxim Solodovnik",
        "email": "solomax666@gmail.com",
        "time": "Wed Oct 28 08:20:37 2026 +0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 28 08:20:37 2026 +0700"
      },
      "message": "[OPENJPA-3026] Windows build should be fixed (#231)"
    },
    {
      "commit": "e6eed60813b6be7a07f6a8f77cab5c1cf1098297",
      "tree": "3dea3e6ed5647d991def40e415d7d3c668c7b954",
      "parents": [
        "a0ac2307e8a5f17f24b6015caca7cfd12ff7387f"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Tue Oct 27 19:24:21 2026 +0100"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Tue Oct 27 19:24:21 2026 +0100"
      },
      "message": "[OPENJPA-3031] Use try-with-resources in the test\n"
    },
    {
      "commit": "a0ac2307e8a5f17f24b6015caca7cfd12ff7387f",
      "tree": "f84454442899fd79f2db34a7ffbe32a586d15315",
      "parents": [
        "963045ecf116faddf6fc8130948222674f0fb874"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Tue Oct 27 17:56:15 2026 +0100"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Tue Oct 27 18:09:33 2026 +0100"
      },
      "message": "[OPENJPA-3030] Render LEFT and RIGHT with SUBSTR on Derby\n"
    },
    {
      "commit": "963045ecf116faddf6fc8130948222674f0fb874",
      "tree": "8961dcd0363bce6328fa709258e6596e51fe4866",
      "parents": [
        "a2e9c6efe63eae61261bfaf159a53ee2ada0c192"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Tue Oct 27 17:49:10 2026 +0100"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Tue Oct 27 18:09:33 2026 +0100"
      },
      "message": "[OPENJPA-3031] Give VARCHAR casts a length on Derby\n"
    },
    {
      "commit": "a2e9c6efe63eae61261bfaf159a53ee2ada0c192",
      "tree": "0b048f6b987d9e421e9375a2676976b5cf70e712",
      "parents": [
        "933e6bb8c67cadd2854551f30d910b6f8719f6fa"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "13417392+rzo1@users.noreply.github.com",
        "time": "Mon Oct 26 13:11:43 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 26 19:11:43 2026 +0700"
      },
      "message": "[OPENJPA-3023] Cache the database value of a converted attribute (#226)\n\n* [OPENJPA-3023] Cache the database value of a converted attribute\n\nThe data cache kept the value of an attribute with an AttributeConverter\nas the Java object and handed the same objects to every persistence\ncontext that loaded the instance from the cache, so a change made in\nplace in one context reached the others. The cache now holds the value\nthe converter writes to the database and runs the converter again when\nthe instance is loaded, so each persistence context gets its own copy.\nThis covers attributes converted as a whole and collections whose\nelements are converted one by one. Arrays and dates returned by a\nconverter are copied on the way into and out of the cache.\n\n* [OPENJPA-3023] Use pattern matching for the Date copy"
    },
    {
      "commit": "933e6bb8c67cadd2854551f30d910b6f8719f6fa",
      "tree": "ce80d7f7f91c18f5b75a238da41210a1d1ea1909",
      "parents": [
        "4d47315722cc71123566d6f61ee498c8c563cdd9"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "13417392+rzo1@users.noreply.github.com",
        "time": "Mon Oct 26 13:10:03 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 26 19:10:03 2026 +0700"
      },
      "message": "[OPENJPA-3022] Do not cache unflushed changes when loading fields of a dirty instance (#225)\n\n* [OPENJPA-3022] Do not cache unflushed changes when loading fields of a dirty instance\n\n* [OPENJPA-3022] Add braces and use try-with-resources in the test"
    },
    {
      "commit": "4d47315722cc71123566d6f61ee498c8c563cdd9",
      "tree": "cb749df67dec5c2685c23957f4684e036df5ab1e",
      "parents": [
        "03df6f4694316c4f23a88a80ebee959a3c3d4f83"
      ],
      "author": {
        "name": "Maxim Solodovnik",
        "email": "solomax@apache.org",
        "time": "Mon Oct 26 12:57:14 2026 +0700"
      },
      "committer": {
        "name": "Maxim Solodovnik",
        "email": "solomax@apache.org",
        "time": "Mon Oct 26 12:57:14 2026 +0700"
      },
      "message": "[OPENJPA-3003] mysql and postgresql\n"
    },
    {
      "commit": "03df6f4694316c4f23a88a80ebee959a3c3d4f83",
      "tree": "12b96173cebfeea8ff8a26297495657d90054733",
      "parents": [
        "f77551bd60e6cf358052b065893b057dff3ebf8f"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "13417392+rzo1@users.noreply.github.com",
        "time": "Mon Oct 26 03:09:15 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 26 09:09:15 2026 +0700"
      },
      "message": "[OPENJPA-3019] Write an in-place change to an element of a collection converted as a whole (#223)\n\n* [OPENJPA-3019] Write an in-place change to an element of a collection converted as a whole\n\nThe proxy of such a collection only sees adds and removes, so a change made\ninside an element was never written. The converted value of these fields is\nnow saved when they are loaded, and compared once before each flush; a field\nwhose converted value differs is marked dirty.\n\n* [OPENJPA-3019] Cover merge, queries and read-only converters in the converted value check\n\n- merge() of a detached instance whose element was changed in place now\n  marks the field dirty when its converted value differs.\n- An AUTO flush before a query checks these fields first.\n- A converter that cannot convert to the database no longer breaks loading.\n- A dirty field is not converted again by the check, and the value written\n  at flush becomes the new saved value.\n\n* [OPENJPA-3019] Note the flush check of converted collections in the migration considerations\n\n* [OPENJPA-3019] Add braces to single statement blocks\n\n* JUnit messages in testOrthanRemoval are improved, additional check is added\n\n---------\n\nCo-authored-by: Maxim Solodovnik \u003csolomax@apache.org\u003e"
    },
    {
      "commit": "f77551bd60e6cf358052b065893b057dff3ebf8f",
      "tree": "c3e943578ee1abd08f9a69720142f759bc9a5e19",
      "parents": [
        "a6faa27ff99c779ace3067a03f9c7deb60c55b47"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "13417392+rzo1@users.noreply.github.com",
        "time": "Mon Oct 26 02:35:02 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 26 08:35:02 2026 +0700"
      },
      "message": "[OPENJPA-3024] Keep orphan removal on a relation that also cascades remove (#224)\n\n* [OPENJPA-3019] test for orphanRemoval case failing for Apache OpenMeetings\n\n* Removal test is improved\n\n* [OPENJPA-3024] Keep orphan removal on a relation that also cascades remove\n\nSince OPENJPA-2940 the annotation parser applied cascade\u003dREMOVE/ALL after\norphanRemoval, so the immediate cascade replaced the dependent marking and\nan element removed from such a collection was no longer deleted. Apply\norphanRemoval last again and remove a dependent value together with its\nowner, as the specification requires for orphanRemoval.\n\n---------\n\nCo-authored-by: Maxim Solodovnik \u003csolomax@apache.org\u003e"
    },
    {
      "commit": "a6faa27ff99c779ace3067a03f9c7deb60c55b47",
      "tree": "dcef628c0547dd0897a28c892b0eec5731e571b0",
      "parents": [
        "544e21ceb37315c80c54f90552881e1a9c5d043c"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "13417392+rzo1@users.noreply.github.com",
        "time": "Sun Oct 25 02:22:57 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 25 08:22:57 2026 +0700"
      },
      "message": "[OPENJPA-3020] Choose the LOB type of a converted attribute from the converter (#222)\n\n* [OPENJPA-3020] Choose the LOB type of a converted attribute from the converter\n\n@Lob and \u003clob/\u003e made a CLOB for a String, char[] or Character[] attribute\nand a BLOB otherwise, before the converter was known, and the converter\u0027s\ntemplate column did not override it. A converter to String on any other\nattribute type therefore got a BLOB, and a converter to byte[] on a String\na CLOB. The converter handlers now set the LOB type from the converter\u0027s\ndatabase type. A byte[] database type is also read as bytes, so the\nconverter no longer gets a java.sql.Blob.\n\n* [OPENJPA-3020] Note the LOB type change of converted attributes in the migration considerations\n\n* [OPENJPA-3020] Add braces to single statement blocks"
    },
    {
      "commit": "544e21ceb37315c80c54f90552881e1a9c5d043c",
      "tree": "6771604850883360f1067c533248474960ee6a1c",
      "parents": [
        "eaeeed3f8703fe6a46d99887e08cc6c0969851d5"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "13417392+rzo1@users.noreply.github.com",
        "time": "Sat Oct 24 03:56:29 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 24 08:56:29 2026 +0700"
      },
      "message": "[OPENJPA-3017] Map a collection whose converter takes the collection itself (#220)\n\n* [OPENJPA-3017] Map a collection whose converter takes the collection itself\n\nA converter declared AttributeConverter\u003cList\u003cX\u003e, Y\u003e converts the attribute\nas a whole, so the field is basic and maps to one column. It was instead\ntreated as having no persistence strategy, left out of the mapping, and its\ncontents were lost without an error.\n\n* [OPENJPA-3017] Use pattern matching for instanceof in resolveConverterTypeArgument\n\n* [OPENJPA-3017] Put a mapping file column of a basic collection on the attribute\n\nA \u003ccolumn\u003e inside \u003cbasic\u003e on a collection or map was assigned to the\nelement mapping unless the value was serialized. A collection converted\nas a whole then failed to map with \"this mapping cannot have columns in\nthis context\". A basic attribute is one value with one column, so its\ncolumn now belongs to the attribute. The converter cannot decide this\nhere, since an @Convert annotation is not parsed yet.\n\n* [OPENJPA-3017] Fetch a collection converted as a whole eagerly by default\n\nA converted attribute is basic, and a basic attribute is eager unless it\nis declared lazy. A collection or map converted as a whole fell back to the\nlazy default of collections, so it was not loaded before detach.\n\n* [OPENJPA-3017] Note converted collections in the migration considerations"
    },
    {
      "commit": "eaeeed3f8703fe6a46d99887e08cc6c0969851d5",
      "tree": "8f69fa09082e9d667c7e1cb94aa086e8b0136c23",
      "parents": [
        "6442d5c1adcfcb45fa76701bda6a5f395e14e1bf",
        "54a8cd7e82db54d143d634557515ea67410f4ad8"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Fri Oct 23 11:10:50 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 23 11:10:50 2026 -0300"
      },
      "message": "Merge pull request #221 from apache/OPENJPA-3018\n\n[OPENJPA-3018] Do not append a size to JSON and JSONB column definitions"
    },
    {
      "commit": "6442d5c1adcfcb45fa76701bda6a5f395e14e1bf",
      "tree": "6243dff7b4348f5ebcc2384f736156243f3ed627",
      "parents": [
        "195b5a0b0a7455ea63b7a71ebf91a485055ccdd2",
        "b30b3ff593e75a4b782178799ad0f7b1cea8cf4d"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Fri Oct 23 11:09:18 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 23 11:09:18 2026 -0300"
      },
      "message": "Merge pull request #218 from apache/OPENJPA-3016\n\n[OPENJPA-3016] Stop two CompUser fixtures sharing a table, and release the EntityManager when a criteria setUp fails"
    },
    {
      "commit": "54a8cd7e82db54d143d634557515ea67410f4ad8",
      "tree": "e2964cfa66f3d741a34869340a9e1421396fde1b",
      "parents": [
        "14f8e0a3b1bfbe4bad5a2dcf5c299fe74cd94b83"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Fri Oct 23 13:36:42 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Fri Oct 23 13:36:42 2026 +0200"
      },
      "message": "[OPENJPA-3018] Share the column helper of the dictionary tests\n"
    },
    {
      "commit": "b30b3ff593e75a4b782178799ad0f7b1cea8cf4d",
      "tree": "6243dff7b4348f5ebcc2384f736156243f3ed627",
      "parents": [
        "fb462594f6d72c6a79912eb4ca25e95d9208cb6d"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Fri Oct 23 13:35:58 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Fri Oct 23 13:35:58 2026 +0200"
      },
      "message": "[OPENJPA-3016] Split the release steps and keep tearDown failures as suppressed\n"
    },
    {
      "commit": "fb462594f6d72c6a79912eb4ca25e95d9208cb6d",
      "tree": "3300ebda573aaa61b84c00fa59ab8a30b44e1e86",
      "parents": [
        "6c912134472277345803455bb7586289e604f4c9"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Tue Oct 13 13:32:05 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Fri Oct 23 13:23:03 2026 +0200"
      },
      "message": "[OPENJPA-3016] Release the EntityManager when a criteria test\u0027s setUp fails\n\njunit.framework.TestCase.runBare() calls setUp() outside its try/finally:\n\n  setUp();\n  try { runTest(); } finally { tearDown(); }\n\nso a failure in setUp() skips tearDown() altogether. CriteriaTest.setUp()\nopens an EntityManager, and a subclass such as TestMultiselect then begins a\ntransaction in its own setUp() to clear the tables, which makes the store\nmanager retain a JDBC connection for the rest of that transaction. When that\nstep failed, the EntityManager and its connection were never released, and\nbecause the criteria base classes keep the EntityManagerFactory in a static\nfield shared by every test class of their hierarchy the leaked connections\naccumulated in one pool.\n\nThe test profiles size that pool at MaxTotal\u003d10 with MaxWait\u003d10s, so about a\ndozen such failures emptied it and every later test in the same JVM failed\nwith\n\n  PersistenceException: Cannot get a connection, pool error Timeout waiting\n  for idle object, maxWaitDuration\u003dPT9.999990575S\n\nrather than with its own problem - which is how one broken schema\nsynchronisation turned into 174 failures and 185 errors in the scheduled\nDatabases run, with TestMultiselect spending 170 seconds purely on pool\ntimeouts.\n\nAbstractCriteriaTestCase.runBare() now runs setUp() inside the guarded block\nand calls tearDown() exactly once either way, which is what JUnit 4 does for\n@Before/@After. For that to help, every criteria base class has to release\nwhat setUp() opened, so the release sequence is hoisted into\nAbstractCriteriaTestCase.releaseResources(): close the EntityManager, clear\nthe audited SQL, close the EntityManagerFactory, drop the references, each\nstep in its own finally so that a failure releasing one resource cannot leave\nthe next one open. CriteriaTest, EmbeddableDomainTestCase and\nJoinDomainTestCase all delegate to it; previously only one of the three was\nhardened, and EmbeddableDomainTestCase did not even reach\nAbstractCriteriaTestCase.tearDown().\n\nTestEmbeddableCriteria deliberately keeps its factory open for the whole\nclass, because rebuilding it would re-run buildSchema(SchemaAction\u003d\u0027drop,add\u0027)\nover the embeddable domain once per test method, and it did so by counting\ntest methods in setUp() and closing the factory in tearDown() only on the\nlast one. With tearDown() now running after a failed setUp() as well, that\ncounter would stop advancing at the first failure and the factory would never\nbe closed again, so the methods are counted in tearDown() instead, the count\nis taken from the class rather than hard coded, and the EntityManager is\nreleased on every method regardless.\n\nThis is deliberately a fix to the test infrastructure and not a larger pool\nor a longer wait, either of which would only postpone the symptom.\n\nTestSetUpFailureReleasesConnection drives three probes. Fourteen of them -\nmore than the pool holds - fail in setUp() after taking a connection in a\ntransaction that writes, and, unlike a real criteria test, release only their\nown EntityManager so that one factory and one pool survive all fourteen; the\ntest affirms after each probe that its EntityManager was closed and at the\nend that the pool still hands out a connection. A second probe closes\ncleanly but throws out of EntityManager.close(), and affirms that the factory\nwas closed all the same. A third repeats the first failure in the\nEmbeddableDomainTestCase hierarchy. The probes live in SetUpFailureProbes\nrather than nested in the Test* class, or surefire reports their deliberate\nfailures as failures of the build whenever the criteria package is selected\nby path.\n\nWithout the runBare() change, the first probe and the EmbeddableDomainTestCase\nprobe fail immediately:\n\n  junit.framework.AssertionFailedError: probe 0 left the EntityManager its\n  setUp() opened behind, so the connection it retained never went back to\n  the pool\n\nand with that assertion removed as well, so that the probes keep leaking, the\nloop reproduces the CI symptom directly - a later probe no longer gets a\nconnection at all:\n\n  org.apache.openjpa.persistence.PersistenceException: Cannot get a\n  connection, pool error Timeout waiting for idle object,\n  maxWaitDuration\u003dPT9.999993S\n\nVerified: the whole criteria package, 544 tests, no failures, on Derby and on\nH2 (-Dtest-h2).\n"
    },
    {
      "commit": "6c912134472277345803455bb7586289e604f4c9",
      "tree": "d98b56658b8258bbd23134edf14e670de48be6f2",
      "parents": [
        "195b5a0b0a7455ea63b7a71ebf91a485055ccdd2"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Tue Oct 13 13:32:05 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Fri Oct 23 13:23:03 2026 +0200"
      },
      "message": "[OPENJPA-3016] Give the common/apps CompUser fixture its own table\n\nTwo unrelated entity hierarchies in the test suite were rooted at a class\ncalled CompUser - org.apache.openjpa.persistence.criteria.CompUser and\norg.apache.openjpa.persistence.common.apps.CompUser - and both defaulted to\na table of that name, with incompatible columns: userid is NOT NULL in one\nand nullable in the other, ADD_ID is BIGINT in one and INTEGER in the other,\nand only the common/apps one has nameAsLob.\n\nWhichever package runs second therefore makes\nSynchronizeMappings\u003dbuildSchema(SchemaAction\u003d\u0027drop,add\u0027) rewrite the table:\nseven ALTER TABLE ... DROP COLUMN followed by seven ALTER TABLE ... ADD, on\nevery EntityManagerFactory it creates. CriteriaTest creates and closes one\nfactory per test method, so a single criteria class rotates every column of\nCompUser dozens of times.\n\nMariaDB executes such an ADD/DROP COLUMN instantly and keeps the dropped\ncolumns in the clustered index record format, counting them towards the\n8126 byte maximum row size. After about a dozen rotations the next statement\nis rejected:\n\n  ALTER TABLE CompUser ADD DTYPE VARCHAR(255)\n  ERROR 1118 (42000): Row size too large. The maximum row size for the used\n  table type, not counting BLOBs, is 8126.\n\nThis is the server\u0027s behaviour, not a defect in OpenJPA or in its MariaDB\ndictionary: replaying the same fourteen statements by hand against an\notherwise untouched InnoDB table fails on the fourteenth cycle, while\ninformation_schema still reports the eight visible columns. MySQL 8.0 does\nnot accumulate the metadata, which is why the scheduled Databases run was\nred only for MariaDB.\n\nNothing about the collision is MariaDB specific, though, so the fixture is\nseparated rather than the dictionary taught to tolerate it: an explicit\n@Table(name \u003d \"CMN_COMPUSER\") keeps the two hierarchies apart and makes the\nsuite independent of the order in which surefire happens to list the test\nclasses - which is what hid this locally, where the criteria package runs\nbefore the jpql one.\n\nThe entity name is unchanged, so the JPQL in the jpql tests (\"FROM CompUser\no\") and the expected SQL in the criteria tests (which names the table\nCompUser) both stay as they are.\n\nReproduced on mariadb:11.8 by running the jpql expressions and functions\npackages first and the criteria package second, on a freshly created\ndatabase: the jpql phase is 123 tests and green either way, and the criteria\nphase goes from 540 tests with 133 failures and 183 errors, 513 of them\nreporting \"Row size too large\", to 544 tests with none. The new test states the\ninvariant directly and fails without the change.\n\nThe MariaDB behaviour is user facing on its own, independent of the test\nsuite: an application configured with\nSynchronizeMappings\u003dbuildSchema(SchemaAction\u003d\u0027drop,add\u0027), or a deployment\nscript running mappingtool -action refresh, rotates the same columns on every\nrestart and eventually fails the same way on a table whose visible columns fit\ncomfortably inside the limit, with nothing in information_schema to hint at\nit. It is therefore written up as a third item under \"Known issues with\nMariaDB\" in supported_databases.xml, naming the remedies - rebuild the table\nwith ALTER TABLE ... FORCE or OPTIMIZE TABLE, or do not use a drop/add schema\naction against a long-lived MariaDB schema - and cross referencing the runtime\nforward mapping section. The file is still well formed: xmllint --noout\nopenjpa-project/src/doc/manual/supported_databases.xml.\n"
    },
    {
      "commit": "14f8e0a3b1bfbe4bad5a2dcf5c299fe74cd94b83",
      "tree": "8ab2d65e78527554e87d9f14571d30cb4f0348be",
      "parents": [
        "195b5a0b0a7455ea63b7a71ebf91a485055ccdd2"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Thu Oct 22 20:36:05 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Thu Oct 22 20:36:05 2026 +0200"
      },
      "message": "[OPENJPA-3018] Do not append a size to JSON and JSONB column definitions\n\nA column definition of jsonb on PostgreSQL, or json on MySQL and MariaDB,\nwas generated with the column length appended, e.g. jsonb(255), which the\ndatabase rejects. These types take no length, so they are now listed as\nfixed size types in the three dictionaries.\n"
    },
    {
      "commit": "195b5a0b0a7455ea63b7a71ebf91a485055ccdd2",
      "tree": "e431578b3c29ddd53f2d8397bb6c6f5888d9c25a",
      "parents": [
        "a2c8177863230fba5c813eb28f5dca7c0d7f26f9"
      ],
      "author": {
        "name": "Maxim Solodovnik",
        "email": "solomax666@gmail.com",
        "time": "Thu Oct 22 15:53:54 2026 +0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 22 15:53:54 2026 +0700"
      },
      "message": "[OPENJPA-2995] comment was added to assertSQL method (#219)"
    },
    {
      "commit": "a2c8177863230fba5c813eb28f5dca7c0d7f26f9",
      "tree": "edbed4fba9567b93050c0368c8058f324347dbdc",
      "parents": [
        "317ed8f8c0d7b4044dc9eeff29a57f9e1ee9a2d9"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "13417392+rzo1@users.noreply.github.com",
        "time": "Mon Oct 19 07:12:12 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 19 12:12:12 2026 +0700"
      },
      "message": "[OPENJPA-2951] Make the context flush after an in-memory bulk operation escapable (#216)\n\nA bulk UPDATE or DELETE that cannot be expressed as a single statement is\nexecuted in memory: OpenJPA loads the matching instances and applies the\noperation to them, so the result is a modified persistence context, not a\nmodified database. The flush added for OPENJPA-2940 therefore carries the\nrow count that executeUpdate() reports to the database - without it an\nem.clear() before the commit discards the operation while the count has\nalready been reported, and a find() after that clear still sees the old\nrow. Measured on Derby with SQL logging: with the flush an in-memory\ndelete emits the owned-table and entity DELETE statements during\nexecuteUpdate() and a find() after em.clear() returns null;\nwithout it only the candidate SELECT is emitted and find() returns the\ninstance again.\n\nThe flush must not turn a legal bulk operation into a failure, though.\nBroker.flush() rejects an incremental flush when the runtime does not\nsupport OPTION_INC_FLUSH - which AbstractStoreManager.getUnsupportedOptions()\ndoes by default, so openjpa-xmlstore raised \"This data store does not\nsupport incremental flushing\" for every bulk delete - and when a savepoint\nis set that the SavepointManager cannot flush incrementally, which the\ndefault in-mem manager cannot. Both rejections happen before anything is\nwritten, but the persistence layer marks the transaction rollback-only on\nthe way out, so the whole transaction was lost where 4.1.x simply applied\nthe operation. The new Broker.isFlushSupported() reports both conditions,\nand the bulk operation now skips the flush and logs it at INFO instead of\nflushing blindly. The pre-flush of the candidate query has always been\nguarded by OPTION_INC_FLUSH in the same way.\n\nThe second cost is that the kernel has no way to flush single instances.\nBrokerImpl.flush(int) is protected, always operates on\ngetTransactionalStates(), fires the flush events with that whole\ncollection, calls afterFlush() on every state and clears\nFLAG_FLUSH_REQUIRED, and the Broker interface exposes only flush() and\npreFlush(); flushing the affected instances alone would need more kernel\nAPI, which is left as a follow-up. So unrelated pending changes are\nwritten as well. Under the default FlushModeType.AUTO that is usually not\na change of its own, because the query that loads the candidates flushes\nthe context first - but that pre-flush of unrelated changes is itself new\nin 4.2.0 (OPENJPA-2940), and it does not happen at all when the query\nnever reaches the datastore, i.e. when the candidates were handed over\nwith setCandidateCollection(): isInMemory() short-circuits the pre-flush\nbefore it looks at the flush mode. The trailing flush is then the only\nflush even under AUTO, which the SQL log confirms - the candidate SELECT\nprecedes the UPDATE of the unrelated instance. The other case is\nFlushModeType.COMMIT, or FlushBeforeQueries\u003dfalse or with-connection\nwithout an open connection, where a dirty instance of a type that is not\non the query\u0027s access path used to stay pending. IgnoreChanges is not\ninvolved: QueryImpl line 1032 short-circuits it for every operation other\nthan OP_SELECT.\n\nThe flush also decides when the AFTER_DELETE_PERFORMED and\nAFTER_UPDATE_PERFORMED callbacks of the affected instances fire, since\nStateManagerImpl.afterFlush() raises them. That is the route most\napplications take into this code: JDBCStoreQuery.executeDelete() gives up\non the single statement precisely when the candidate has delete listeners,\n\"so the callbacks are invoked\".\n\nNeither behaviour is mandated. Jakarta Persistence 3.1 section 4.10\nstates that \"the persistence context is not synchronized with the result\nof the bulk update or delete\" and recommends that \"bulk update and delete\noperations should only be performed within a transaction in a new\npersistence context or before fetching or accessing entities whose state\nmight be affected by such operations\". A reported row count that never\nreached the database is the worse of the two, so the flush stays the\ndefault and becomes escapable through the compatibility option\nFlushAfterInMemoryBulkOperation. Suppressing the flush must not and does\nnot suppress the in-memory application of the operation: the instances\nare still modified or marked for deletion and are written by the next\nflush or at commit.\n\nThe new section of the migration considerations documents the flush, the\npending changes and callbacks it moves, the two cases in which it is the\nonly flush, the option and the fallback when the context cannot be flushed, which\ncovers the flush after the operation only - the flush before the candidate\nquery is not guarded against a savepoint, so an operation issued with\npending changes and a savepoint set still fails as it did before. No test in the tree depended on the flush - the bulk and criteria suites\nall pass with it removed. Six of the twelve new methods in\nopenjpa-persistence-jdbc fail with the kernel part of this change reverted;\nthe other six pin behaviour OPENJPA-2940 already introduced and pass on\nmaster as well. TestInMemoryBulkFlush pins the default,\nincluding the candidate-collection case under AUTO and the savepoint\nfallback on a clean context; four of its six methods assert the candidate\nSELECT so they cannot pass on a datastore-executed operation, and the other\ntwo assert the presence or absence of a single statement; TestInMemoryBulkFlushCompat pins the option;\nTestInMemoryBulkFlushCallbacks pins the callback timing on both paths; and\nTestPersistence of openjpa-xmlstore covers the AbstractStoreManager\ndefault, which had no bulk-operation test at all.\n\nCo-authored-by: Maxim Solodovnik \u003csolomax666@gmail.com\u003e"
    },
    {
      "commit": "317ed8f8c0d7b4044dc9eeff29a57f9e1ee9a2d9",
      "tree": "fe52a49e211d5a770a0aab34486c1496bca71a28",
      "parents": [
        "a525594b01ed2e1d7075464beea2b1859dcbe95d"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "13417392+rzo1@users.noreply.github.com",
        "time": "Mon Oct 19 04:50:55 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 19 09:50:55 2026 +0700"
      },
      "message": "[OPENJPA-3014] Back a named sequence generator by a table, and use real sequences on MariaDB (#217)\n\n* [OPENJPA-3014] Back a named sequence generator by a table where the database has none\n\nA named @SequenceGenerator failed outright on every database whose\ndictionary defines no NextSequenceQuery. AnnotationPersistenceMetaDataParser\nsets the plugin of such a generator to SequenceMetaData.IMPL_NATIVE unless\nthe sequence name is itself a plugin string, JDBCSeqValue maps that alias to\nNativeJDBCSeq, and NativeJDBCSeq.endConfiguration() refuses to configure\nwithout a NextSequenceQuery:\n\n  ArgumentException: Error instantiating named sequence \"SEQGENERATOR\":\n  Your database dictionary does not support native sequences\n\nopenjpa.Sequence cannot help, because SequenceMetaData.instantiate()\nconsults the configured system sequence only for the system sequence name,\nso a named generator always takes the plugin path. There was no property\nthat avoided the failure.\n\nThe report names MySQL, found while running the TCK, but the dictionaries\nwithout a NextSequenceQuery include Apache Derby, so the failure also\nreproduces on the database the default test profile uses; the new test\nfails on Derby, H2 excepted, before this change. They also include\nAbstractSQLServerDictionary, SQLServerDictionary, SybaseDictionary,\nMaxDBDictionary, SolidDBDictionary, HerdDBDictionary, AccessDictionary and\nInterbaseDictionary, and SQL Server has had sequence objects since 2012,\nso there the fallback stands in for a sequence the database could have\nprovided. The migration notes name those databases and say that\nconfiguring NextSequenceQuery is how a generator keeps drawing from a\nsequence that already exists, with a pointer from the SQL Server section.\n\nJakarta Persistence 3.1 section 11.2.4 and the GeneratedValue strategies in\nsection 11.1.21 define how a generator declaration is mapped, and\nGenerationType.SEQUENCE says \"the persistence provider must assign primary\nkeys for the entity using a database sequence\", but the specification\nelsewhere leaves the realisation of a generator to the provider, which is\nwhy providers emulate sequences where a database has none. The observable\ncontract is that identifiers are unique and that initialValue and\nallocationSize are honoured. Resolving a named generator to a table backed\nsequence therefore raises no conformance obstacle; it is a design decision\nwith a compatibility dimension, not something the specification demands.\n\nSequenceMapping.instantiate() now substitutes a value table sequence when\nthe plugin is a plain request for a native sequence and\ndict.nextSequenceQuery is null, gated on the dictionary\u0027s own property\nrather than on a dictionary class so that a user supplied NextSequenceQuery\nkeeps the native path. The substitution sits where the sequence is\nresolved, so the runtime and the mapping tool agree - a patch proposed on\nthe dev list changed only MappingTool.addSequenceComponents, which leaves a\nplain EntityManagerFactory failing and works by mutating shared metadata.\nInstead of mutating this SequenceMapping, which is shared, the fallback\nbuilds a separate metadata instance and instantiates that; the substitution\nis logged as a warning, once per generator, because the sequence instance is\ncached on the metadata.\n\nValueTableJDBCSeq rather than TableJDBCSeq: ValueTableJDBCSeq keys its\ncounter row by a name, so the row is keyed by the sequence name the\ngenerator asked for and entities sharing one generator share one counter,\nas they would with a real sequence. TableJDBCSeq keys the row per class and\nwould give each entity an independent counter, which is neither the\nannotation\u0027s semantics nor what the native path does. The sequence name is\nqualified with the catalog and schema of the sequence, so that two\nsequences of the same name in different schemas stay distinct without the\ninternal table having to live in a schema the generator meant for a\nsequence object. That schema is the one a sequence object would have been\ncreated in: the generator\u0027s own, or, when it declares none,\nthe persistence unit default that SequenceMetaData.setSchema substitutes.\nThe emulated counter is therefore scoped exactly as the sequence it stands\nin for, which the Javadoc, the migration notes and a test with a qualified\ngenerator now say.\n\ninitialValue and allocationSize travel on the SequenceMetaData rather than\nin the plugin string and are copied onto the substitute, which the test\nasserts both on the resulting Seq and through the identifiers it hands out,\nby counting the statements that advance the generator\u0027s counter: one\nallocation per block of allocationSize, not one per identifier.\nThe increment is deliberately not copied: TableJDBCSeq.setIncrement is a\ndeprecated alias for setAllocate and, appended after Allocate, would\noverwrite the allocation size.\n\nopenjpa.Compatibility\u003dEmulateNativeSequences\u003dfalse restores the hard\nfailure. The default is the fallback, because the behaviour it replaces is\nan unconditional failure with no workaround, so nothing that works today\nchanges; a schema built by an earlier release will simply gain the sequence\ntable.\n\nA dictionary identified from the connection URL alone has not seen a\nconnection when the generator is resolved, and some dictionaries only learn\nfrom the server version whether the database has sequences, so where the\ndictionary itself declares no NextSequenceQuery the gate asks the\nconfiguration for its connection factory, which installs the dictionary\u0027s\nconnected configuration. Otherwise which sequence backs a generator would\ndepend on whether anything else had touched the database first. The cheap\ncheck comes first, so a dictionary that sets NextSequenceQuery in its\nconstructor - Oracle, DB2, PostgreSQL, H2, HSQL, Informix, Firebird,\nIngres - is still resolved without a connection and an offline mapping tool\nrun against such a configuration does not stall on a connect attempt.\nDBDictionary.isConnected() exposes the connected state.\n\nIf that connect attempt fails, the generator fails to resolve, with the\nconnect failure as the cause of a MetaDataException, rather than falling\nback. Guessing cannot help there - the table fallback advances its counter\nover a connection of its own, so nothing hands out an identifier without\none either way - and it can harm: SequenceMetaData.getInstance caches the\nSeq, so the guess holds for the life of the factory, and a node of a\nclustered deployment whose JNDI lookup happened to fail would then hand out\nidentifiers from a counter the other nodes do not use. That is the same\ndivergence the sibling commit avoids by parsing the version prefix, and a\nlog warning is not a sufficient signal for it. A missing driver class\narriving as a LinkageError is wrapped alongside the runtime exceptions.\n\nThe test asks the dictionary which kind of database it is on rather than\nassuming, because both kinds exist and the same observable contract has to\nhold on both. Whether a database has sequence objects is\nDBDictionary.nextSequenceQuery, which a dictionary may only set once it has\nseen the server, so the test connects it exactly as the fallback above\ndoes - DBDictionary.isConnected(), then JDBCConfiguration\n.getConnectionFactory() - before reading it; reading it off an unconnected\ndictionary would expect the fallback on a server that has sequences. The\nunique identifiers, the initialValue and the allocation count are asserted\non both paths. Only which Seq implementation backs the generator, and that\nEmulateNativeSequences\u003dfalse brings the old failure back, are specific to\nthe fallback; the latter is skipped with a message naming the platform\nwhere the database has sequences. The allocation count is measured as the\nnumber of statements that advance the counter, which is the UPDATE of the\ncounter row on the fallback and the dictionary\u0027s NextSequenceQuery - for\ninstance SELECT NEXTVAL(OJPA3014_SEQ) - on the native path, with the\nCREATE SEQUENCE and the ALTER SEQUENCE ... INCREMENT BY excluded, since\nneither hands out a value.\n\nOn a database that has sequence objects that test only re-asserts the\nnative path: of the five cases, four hold on master there as well, and only\nthe Derby half of the CI matrix sees the substitution end to end. The gate\nitself is therefore covered server free by the new\nTestSequenceMappingFallback in openjpa-jdbc, which drives\nSequenceMapping.instantiate() with a stub dictionary and a stub DataSource\non every platform: a dictionary that learns of sequence support only in\nconnectedConfiguration() reaches NativeJDBCSeq, one that never declares any\nreaches ValueTableJDBCSeq with the sequence name, initialValue and\nallocationSize carried over, one that declares NextSequenceQuery in its\nconstructor is resolved without the data source being touched at all, a\ndata source that cannot connect makes the resolution fail with its own\nSQLException reachable in the cause chain, and\nEmulateNativeSequences\u003dfalse brings the historical failure back.\n\n* [OPENJPA-3014] Use real sequences on MariaDB 10.3 and later\n\nMariaDB 10.3 introduced sequence objects - CREATE SEQUENCE, NEXTVAL(),\nNEXT VALUE FOR - but MariaDBDictionary still declared no\nNextSequenceQuery, so every @SequenceGenerator was treated as\nunsupported. Set it in connectedConfiguration() once the server reports\n10.3 or later, the way PostgresDictionary version gates\nstoreCharsAsNumbers. Older servers keep the table sequence fallback.\n\nMariaDBDictionary.java:57 reads \"public class MariaDBDictionary extends\nDBDictionary\": the dictionary is a copy of the MySQL one, not a subclass\nof it, down to a private getMajorMinorVersions of its own at line 244.\nNothing here is inherited, and MySQLDictionary is untouched.\n\nThere is no setter for NextSequenceQuery and hence no flag recording that\nthe user configured one, and this change does not invent one: this\ndictionary leaves the field null in its constructor and\nDBDictionary.endConfiguration() nulls an empty value out, so a value seen\nin connectedConfiguration() was configured explicitly and is left alone.\n\nA MariaDB 10.x server reports its version to a client that is not MariaDB\naware with a replication compatibility prefix - \"5.5.5-10.3.39-MariaDB\"\nrather than \"10.3.39-MariaDB\". The prefix was dropped in 11.0, so an 11.x\nserver reports \"11.8.9-MariaDB-ubu2404\" to any client; both forms were read\noff the handshake greeting of mariadb:10.3 and mariadb:11.8 to confirm it. Both forms reach\nthis dictionary, but not by the same route: DBDictionaryFactory\n.newDBDictionary selects on getDatabaseProductName(), falls back to the URL\nprotocol, and looks at getDatabaseProductVersion() only when the name maps\nto MySQL (lines 93-102). With mariadb-java-client the product name is\nalready \"MariaDB\" and the version string plays no part in the selection;\nthe prefixed form matters because MySQL Connector/J reports the product\nname as \"MySQL\", so for that client the version string is both what selects\nthis dictionary and what carries the prefix. What the version parsing has\nto cope with is the prefix itself, because it stops at the first character\nthat is neither a digit nor a dot: on the prefixed form it would read 5.5\nand withhold sequence support from an 11.8 server reached through a driver\nthat passes the handshake version through, while the same server reached\nthrough mariadb-java-client used a sequence object - two deployments of one\napplication handing out identifiers from two independent counters. Strip\nthe prefix before parsing.\n\nThe strip moves every feature this dictionary gates on the version, not\nonly sequence support. The pre-existing gate for 10.2 and later\n(maj \u003e 10 || (maj \u003d\u003d 10 \u0026\u0026 min \u003e 1)) sets\ntimestampTypeName\u003d\"DATETIME{0}\", moves it into fractionalTypeNameSet and\nsets dateFractionDigits\u003d6, so a server reported as \"5.5.5-10.2.44-MariaDB\"\nnow gets microsecond DATETIME columns where it was parsed as 5.5 and got\nwhole-second DATETIME before - the same DDL the same server already got\nthrough mariadb-java-client. TestMariaDBDictionary pins both forms of a\n10.2 version to DATETIME{0}/6 and a genuine 10.1 version to DATETIME/0,\nand the MariaDB section of the migration notes says that such a deployment\nnow generates microsecond columns, that a schema from an earlier release\nkeeps its whole-second ones, and that the gate assigns both fields\noutright, so only a subclass restores the previous types.\n\nDeclaring sequence support means the schema tool now issues CREATE SEQUENCE\nand DROP SEQUENCE for these generators, which brings two more things with\nit:\n\n- MariaDB caches 1000 increments of a sequence per server by default and\n  discards what is left of that range whenever the cache is flushed, which\n  an ALTER SEQUENCE or a restart does. OpenJPA caches values itself, in\n  blocks of the generator\u0027s allocation size, and NativeJDBCSeq issues\n  ALTER SEQUENCE ... INCREMENT BY once per sequence instance to do so,\n  which is itself such a flush, so the server side cache adds nothing but\n  those gaps. getCreateSequenceSQL() therefore creates sequences with\n  NOCACHE. Measured on MariaDB 11.8 against a sequence created START WITH\n  100 INCREMENT BY 7: SELECT NEXTVAL returns 100 and leaves\n  NEXT_NOT_CACHED_VALUE at 7100, and after ALTER SEQUENCE ... INCREMENT BY\n  7 the next SELECT NEXTVAL returns 7100 - 1000 increments skipped, not\n  1000 values. With NOCACHE the same statements return 100 and then 107.\n\n  The statements OpenJPA emits for a generator with initialValue 100 and\n  allocationSize 7, as the SQL that TestNamedSequenceGenerator collects\n  shows them on MariaDB 11.8, are\n\n    CREATE SEQUENCE OJPA3014_SEQ START WITH 100 INCREMENT BY 7 NOCACHE\n    ALTER SEQUENCE OJPA3014_SEQ INCREMENT BY 7\n    SELECT NEXTVAL(OJPA3014_SEQ)\n\n  - unquoted, and with no CYCLE clause. The 7 in INCREMENT BY is\n  increment * allocate, which DBDictionary.commonCreateAlterSequenceSQL\n  multiplies out; NativeJDBCSeq leaves the increment at its default of 1,\n  so for this generator it is the allocation size. In that order no jump\n  occurs, the ALTER arriving before the first NEXTVAL has cached anything,\n  and 15 identifiers cost three NEXTVALs; the jump is what a later\n  EntityManagerFactory would see, issuing the ALTER against a sequence\n  whose values have been cached, and that is the case NOCACHE covers.\n\n- Reflecting on the schema to find existing sequences needs a query, since\n  DatabaseMetaData does not report them. MariaDB has no\n  INFORMATION_SCHEMA.SEQUENCES before 10.6, but a sequence appears in\n  INFORMATION_SCHEMA.TABLES with a TABLE_TYPE of SEQUENCE in every version\n  that has sequences, so getSequencesSQL() reads it from there. The schema\n  name is matched case insensitively because DBDictionary.getSequences()\n  upper cases the schema it passes, while MariaDB keeps the case a schema\n  was created with. INFORMATION_SCHEMA spans every database on the server,\n  though, and every caller asks for a null schema - SchemaGenerator\n  .generateSequences() passes DBIdentifier.NULL deliberately, and an\n  unqualified @SequenceGenerator has none - so the unqualified case is\n  scoped to DATABASE(). Unrestricted it would report the sequences of other\n  applications\u0027 databases, which makes SchemaTool.buildSchema() skip a\n  CREATE SEQUENCE it owes, because SchemaGroup.findSequence() matches any\n  schema for an unqualified sequence, and makes a retain, refresh or dropDB\n  action issue DROP SEQUENCE outside the configured database. DATABASE()\n  takes no bind parameter, so the parameter indices getSequences() binds\n  stay as they were.\n\nTestMariaDBDictionary drives connectedConfiguration() with a reflection\nproxy DatabaseMetaData, as TestPostgresDictionary does for OPENJPA-2971, so\nthe version gate, the survival of an explicitly configured\nNextSequenceQuery, the generated temporal types, the NOCACHE suffix and the\npredicates and binding order of the sequence query are covered without a\nserver: 18 tests, all passing. TestNamedSequenceGenerator passes on Derby\nand H2, the two profiles CI runs, and passed on MariaDB 10.2 and 11.8 and\nMySQL 8.0 when it was measured there, which is where the SQL quoted above\nwas collected.\n\n---------\n\nCo-authored-by: Maxim Solodovnik \u003csolomax666@gmail.com\u003e"
    },
    {
      "commit": "a525594b01ed2e1d7075464beea2b1859dcbe95d",
      "tree": "fe1e3829c8158b3d63f9887cd7f3c2203ab496dc",
      "parents": [
        "d5788d3120ab0e6caf07f02edc22166ad9fb3af8",
        "49bbeb84f52ab9f44071e87cd214ed2afed8fd20"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Sun Oct 18 09:18:18 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 18 09:18:18 2026 -0300"
      },
      "message": "Merge pull request #215 from apache/OPENJPA-2950\n\n[OPENJPA-2950] Flush before a query for the access path, not for the whole context"
    },
    {
      "commit": "d5788d3120ab0e6caf07f02edc22166ad9fb3af8",
      "tree": "b7f01f9a3c878ad2d08d4e78a6345eb821e15448",
      "parents": [
        "27738fc257bcebc2bdd4d2191f4821d56d7f9ba1",
        "b94c1e56ec0d815686d47bdf17337b082cc4b05c"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Tue Oct 13 21:14:41 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 13 21:14:41 2026 -0300"
      },
      "message": "Merge pull request #213 from apache/tck-mysql\n\n[OPENJPA-3001] TCK related MySQL improvements"
    },
    {
      "commit": "27738fc257bcebc2bdd4d2191f4821d56d7f9ba1",
      "tree": "037e07ffe109e43d2009df7fc16a517da6aa45fd",
      "parents": [
        "ace0ff4c9a63eb4e74225fff1149fa7c5d65d7a8",
        "54638fdda94ca9f564d969cb7e2e30c6a3640dcc"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Tue Oct 13 21:13:57 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 13 21:13:57 2026 -0300"
      },
      "message": "Merge pull request #214 from apache/OPENJPA-3015\n\n[OPENJPA-3015] Mail the dev list when a workflow run fails"
    },
    {
      "commit": "49bbeb84f52ab9f44071e87cd214ed2afed8fd20",
      "tree": "cd1fba78d6acbb51ae10e0a9bc66079fc0a47ad2",
      "parents": [
        "ace0ff4c9a63eb4e74225fff1149fa7c5d65d7a8"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Tue Oct 13 09:37:06 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Tue Oct 13 11:17:27 2026 +0200"
      },
      "message": "[OPENJPA-2950] Flush before a query only for the types it reads\n\nSince OPENJPA-2940 a query with FlushModeType.AUTO flushed as soon as anything\nin the persistence context was dirty, and overrode openjpa.IgnoreChanges\nwhenever the flush mode was AUTO - which is the default. Both are reverted, and\nthe gap the broadening was meant to close is fixed where it actually is.\n\nWhy the access path is enough. Section 3.10.8 of the specification scopes the\nduty to the updates \"which could potentially affect the result of the query\",\nand lets the provider discharge it \"by flushing those entities to the database\nor by some other means\". A full-context flush is therefore permitted but not\nrequired, and the access path check is exactly such other means: only a dirty\ninstance of a type the query reads can change its result. That holds, however,\nonly for as long as the access path is complete, and in two places it was not.\n\nJPQL. AbstractExpressionBuilder.traversePath() registered the metadata of every\nhop, so Order, Customer and Spouse are all in the access path of \"SELECT o FROM\nOrder o WHERE o.customer.spouse.lastName \u003d \u0027Miller\u0027\" - the case the comment\nadded with the broadening claimed was missed. What it did miss is a collection-\nor map-valued path used without a join variable: the declared type of such a\nfield is Collection or Map, which has no metadata, so SIZE(x.coll) and\nx.coll IS EMPTY left the element and key types out and a dirty element was not\nflushed. traversePath() now registers them, which also makes the JPQL and the\nCriteria side agree - the latter registers them for the same field.\n\nCriteria. CriteriaExpressionBuilder.evalAccessPaths() looked only at the roots\nand their immediate joins, so a type reached by an implicit join (a path\nnavigated with Path.get), by a join of a join, by a fetch join, inside a\nsubquery or behind a join made on a correlated join was left out - the subquery\ncase was a standing \"TODO -- need to handle subqueries\". That is now fixed at\nthe source: PathImpl registers each field it traverses on the query, SubqueryImpl\nhands its access path to the enclosing query, the join walk follows the whole\njoin tree and starts at the correlated joins of the enclosing subquery as well,\nand CriteriaExpressionBuilder merges all of it into QueryExpressions.accessPath\nafter the expressions have been converted.\n\nIgnoreChanges. openjpa.IgnoreChanges\u003dtrue is a documented option whose purpose\nis to let a query run straight against the datastore, recommended in\nref_guide_optimization.xml together with the default\nopenjpa.FlushBeforeQueries\u003dtrue. Overriding it whenever the flush mode is\nFLUSH_TRUE therefore silently removed it for every default configuration. It is\nrestored unconditionally, as in 4.1.x, and no distinction is drawn between a\nflush mode set on the query and one inherited from the persistence context:\nsection 3.10.8 states the same duty for both triggers, so there is no basis for\nhonouring the option for one and not the other. The option is an OpenJPA\nextension that opts a SELECT out of that duty, which ref_guide_conf.xml now\nsays where users enable it.\n\nMaking the override conditional on the flush mode would also have required\nstate the facade does not have. Writing through to the kernel\u0027s ignoreChanges\ninstead, as this was first implemented, is not sound: the write is one-way, so\nsetFlushMode(AUTO) followed by setFlushMode(COMMIT) on the same query left\nignoreChanges false with flush FLUSH_FALSE, and QueryImpl.isInMemory() then\nentered the branch, could not flush and executed the query in memory over the\nwhole extent - a different result set and an unbounded scan for the same query\ntext and flush mode. It also fired for queries the application never set a flush\nmode on, because EntityManagerFactoryImpl.addNamedQuery() captures a flush mode\nthat is never unset and createNamedQuery() replays it as setFlushMode(AUTO).\n\nThe prohibitions of section 3.10.8 hold. _broker.isActive() already covers \"if\nthere is no transaction active, the persistence provider must not flush\"; an\nunjoined context cannot reach the flush at all, because\nEntityManagerFactoryImpl rejects SynchronizationType.UNSYNCHRONIZED.\n\nNo compatibility option is added: the broadened behaviour only ever existed on\nthe unreleased 4.2.0 line, so there is nothing to be compatible with. The\nmigration note is rewritten to describe what actually changes for an\napplication upgrading from 4.1.x.\n\nTests, asserting on emitted SQL rather than on results, because a full-context\nflush returns the same results:\n- TestQueryFlushAccessPath: a dirty instance of a type outside the access path\n  must not flush; the candidate type, a dirty subclass of it, a type reached by\n  JPQL navigation, a collection path in SIZE() and in IS EMPTY, and - for the\n  Criteria API - an implicit join, a join of a join, a fetch join, a subquery\n  and a join made on a correlated join must all be visible; COMMIT must not\n  flush; no flush without an active transaction.\n- TestQueryFlushIgnoreChanges: IgnoreChanges\u003dtrue keeps suppressing the flush\n  for an inherited flush mode, for AUTO set on the query, across a\n  setFlushMode(AUTO)-then-COMMIT sequence and through an addNamedQuery() /\n  createNamedQuery() round trip.\nEach hunk is discriminated by reverting it alone: the kernel access-path hunk by\nthe two collection-path tests, the correlated-join hunk by the correlated-join\ntest, openjpa-persistence/.../criteria/ by the five Criteria tests, and the\nQueryImpl hunk by three of the four IgnoreChanges tests, each on an\nassertNotSQL for an UPDATE that should not have been emitted.\n\nReverting the whole diff at once does not discriminate, and deliberately so:\nseven of the eighteen tests pass against master as well, because the blanket\nflush there masks the incomplete access paths - everything is flushed anyway.\nThose seven are regression guards (dirty candidate type, dirty subclass, JPQL\nnavigation, subquery type, COMMIT, no active transaction, AUTO-then-COMMIT),\nand the two navigation ones also back up the finding that traversePath already\ncovered o.customer.spouse.\n"
    },
    {
      "commit": "54638fdda94ca9f564d969cb7e2e30c6a3640dcc",
      "tree": "037e07ffe109e43d2009df7fc16a517da6aa45fd",
      "parents": [
        "ace0ff4c9a63eb4e74225fff1149fa7c5d65d7a8"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Tue Oct 13 09:43:11 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Tue Oct 13 09:43:11 2026 +0200"
      },
      "message": "[OPENJPA-3015] Mail the dev list when a workflow run fails\n\nThe scheduled Databases workflow runs weekly and a failure went unnoticed\nuntil someone happened to look. The jobs notification scheme mails a run that\nfails, and one that succeeds after a series of failures; successful runs are\nnot mailed.\n"
    },
    {
      "commit": "b94c1e56ec0d815686d47bdf17337b082cc4b05c",
      "tree": "d2cf228f3bf2591b94a94374544841e6625ee8b6",
      "parents": [
        "4c6e0c84c5ae4a89891de5c9ca1ddf6aff8542f9"
      ],
      "author": {
        "name": "Maxim Solodovnik",
        "email": "solomax@apache.org",
        "time": "Mon Oct 12 12:06:39 2026 +0700"
      },
      "committer": {
        "name": "Maxim Solodovnik",
        "email": "solomax@apache.org",
        "time": "Mon Oct 12 12:06:39 2026 +0700"
      },
      "message": "[OPENJPA-3001] nextSequenceQuery is set for MariaDBDictionary; supported_databases is updated for MySQL\n"
    },
    {
      "commit": "4c6e0c84c5ae4a89891de5c9ca1ddf6aff8542f9",
      "tree": "5b49abac44f289673933fbb6fd90506f9d2e2842",
      "parents": [
        "3b91c6e8de4036b20c6abba194a68791ede20ad2"
      ],
      "author": {
        "name": "Maxim Solodovnik",
        "email": "solomax@apache.org",
        "time": "Thu Oct 08 21:20:20 2026 +0700"
      },
      "committer": {
        "name": "Maxim Solodovnik",
        "email": "solomax@apache.org",
        "time": "Mon Oct 12 08:49:38 2026 +0700"
      },
      "message": "[OPENJPA-3001] storeCharsAsNumbers is turned off for MySQL by default\n"
    },
    {
      "commit": "3b91c6e8de4036b20c6abba194a68791ede20ad2",
      "tree": "b94e5432aae7f4ec9e56073098eb5f2be1fe89e0",
      "parents": [
        "ace0ff4c9a63eb4e74225fff1149fa7c5d65d7a8"
      ],
      "author": {
        "name": "Maxim Solodovnik",
        "email": "solomax@apache.org",
        "time": "Wed Oct 07 13:09:58 2026 +0700"
      },
      "committer": {
        "name": "Maxim Solodovnik",
        "email": "solomax@apache.org",
        "time": "Mon Oct 12 08:49:38 2026 +0700"
      },
      "message": "[OPENJPA-3001] investigating test failures\n"
    },
    {
      "commit": "ace0ff4c9a63eb4e74225fff1149fa7c5d65d7a8",
      "tree": "a64db2126849be6aa7440b70ac267e4056f8f2d0",
      "parents": [
        "248c65317020eb81eee85902533997322bb42b65",
        "c234e2c14f6ac27e7c7415b3dc6085fd04731f3a"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Sun Oct 11 10:52:25 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 11 10:52:25 2026 -0300"
      },
      "message": "Merge pull request #212 from apache/OPENJPA-3013\n\n[OPENJPA-3013] Collect the candidate loaders without a MultiClassLoader"
    },
    {
      "commit": "c234e2c14f6ac27e7c7415b3dc6085fd04731f3a",
      "tree": "a64db2126849be6aa7440b70ac267e4056f8f2d0",
      "parents": [
        "248c65317020eb81eee85902533997322bb42b65"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Fri Oct 09 14:31:25 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Fri Oct 09 14:31:25 2026 +0200"
      },
      "message": "[OPENJPA-3013] Collect the candidate loaders without a MultiClassLoader\n\nThe loaders to consult were collected into a MultiClassLoader and unwrapped\nagain, which only served to keep the protected hook that contributes them.\nCollect them into a list and build the array from it instead.\n\nThe hook therefore takes a List\u003cClassLoader\u003e; the MultiClassLoader overload is\ndeprecated for removal and no longer called, so a subclass overriding it has to\nmove to the new signature.\n"
    },
    {
      "commit": "248c65317020eb81eee85902533997322bb42b65",
      "tree": "1c2268554271867bc5a9802a687b592e3423b0fb",
      "parents": [
        "921891068d9ec1de422f10515bef11dfb9b29407"
      ],
      "author": {
        "name": "Maxim Solodovnik",
        "email": "solomax666@gmail.com",
        "time": "Fri Oct 09 18:40:51 2026 +0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 09 18:40:51 2026 +0700"
      },
      "message": "[OPENJPA-3012] some comments are addressed (#211)\n\n* [OPENJPA-3012] some comments are addressed\n\n* [OPENJPA-3012] Test the class resolution of the deserializing stream\n\nThe resolution paths are reachable without constructing an ObjectStreamClass:\nserializing int.class yields a descriptor whose name is \"int\", which\nClass.forName rejects, so it is resolved only by the fallback to the stream\u0027s\nown resolveClass; that test fails before this change and passes after it. A\nclass loader that redefines the classes of the test instead of delegating gives\na class reachable from one loader only, which pins that the thread context\nloader is consulted and takes precedence. Array classes and an array instance\ncover the descriptors that name a type rather than a class.\n\n---------\n\nCo-authored-by: Richard Zowalla \u003crzo1@apache.org\u003e"
    },
    {
      "commit": "921891068d9ec1de422f10515bef11dfb9b29407",
      "tree": "21fcc61196ff01bad08cc26d98b95e24ecfee389",
      "parents": [
        "68fe1f2448f2ea1c905b94f75e0b4a957531b0e5",
        "bbae53b83d32016c6e174279999e68e780136b3a"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Fri Oct 09 06:18:34 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 09 06:18:34 2026 -0300"
      },
      "message": "Merge pull request #210 from apache/OPENJPA-3012\n\n[OPENJPA-3012] no new classloaders are being registered in ClassResolvingObjectInputStream.resolveClass"
    },
    {
      "commit": "68fe1f2448f2ea1c905b94f75e0b4a957531b0e5",
      "tree": "af4cb57c31b61ed4f7c0352478d7d3d8d397493f",
      "parents": [
        "d1f653b1cd4286c6985ec700b1e2f6cbbf0f09af",
        "023836e4d037d12c7bf39574d32bac0b39daef98"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Fri Oct 09 06:15:32 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 09 06:15:32 2026 -0300"
      },
      "message": "Merge pull request #209 from apache/OPENJPA-3011\n\n[OPENJPA-3011] Run the other dictionaries on a schedule"
    },
    {
      "commit": "023836e4d037d12c7bf39574d32bac0b39daef98",
      "tree": "5c7740947e0cc9ca1c5bfcc967f4576a0aa771d9",
      "parents": [
        "b4bfa57f0c03f07a2c3053ff9a9820ec94471ae9"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Thu Oct 08 17:40:06 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Fri Oct 09 09:32:11 2026 +0200"
      },
      "message": "[OPENJPA-3011] Run the other dictionaries on a schedule\n\nThe pull request build covers Derby and H2 only, so a defect that is invisible\non those two reaches master and is found when a committer runs another database\nby hand: a JPQL LIKE pattern matched only on Derby for several releases\n(OPENJPA-3009) and six tests asserted the SQL shape Derby and H2 emit\n(OPENJPA-3010). Run the existing MySQL, MariaDB and PostgreSQL docker profiles\nweekly instead, and on demand.\n\nThe docker-maven-plugin declarations in those profiles carry configuration but\nno executions, so nothing starts a container during an ordinary build; the\nservers come from service containers with health checks, with the credentials\nthe respective profile expects. One job per database, because MySQL and MariaDB\nboth listen on 3306 and a service container cannot be selected per matrix entry.\n\nA scheduled run on an unchanged tree would only repeat the previous one, so it\nis skipped unless something was committed within the week, and a scheduled run\nis refused on any branch but the default one. A manual run always proceeds, so\na risky change can be tried on its own branch before it lands.\n"
    },
    {
      "commit": "bbae53b83d32016c6e174279999e68e780136b3a",
      "tree": "491f8a9ff85ad788b430b5cb4988d4330df019cc",
      "parents": [
        "d1f653b1cd4286c6985ec700b1e2f6cbbf0f09af"
      ],
      "author": {
        "name": "Maxim Solodovnik",
        "email": "solomax@apache.org",
        "time": "Fri Oct 09 13:00:16 2026 +0700"
      },
      "committer": {
        "name": "Maxim Solodovnik",
        "email": "solomax@apache.org",
        "time": "Fri Oct 09 13:00:16 2026 +0700"
      },
      "message": "[OPENJPA-3012] no new classloaders are being registered in ClassResolvingObjectInputStream.resolveClass\n"
    },
    {
      "commit": "d1f653b1cd4286c6985ec700b1e2f6cbbf0f09af",
      "tree": "cfad87379cc410870c17587703ad3ede8708edc7",
      "parents": [
        "042caefefd40518ca043683f125e51e4d7f12539",
        "1f919c3297525215d18db1bbe86e8c8403ae4325"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Thu Oct 08 21:34:38 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 08 21:34:38 2026 -0300"
      },
      "message": "Merge pull request #208 from apache/OPENJPA-3009\n\n[OPENJPA-3009] Make a JPQL LIKE without ESCAPE mean the same on every database"
    },
    {
      "commit": "042caefefd40518ca043683f125e51e4d7f12539",
      "tree": "69e4b31926815ff1cf787a8e318ea2ae8e72aeb4",
      "parents": [
        "b09ee3e2f6bd0fcaddd275cf3c76024d4f304e04",
        "00064aa235e2702e6dc57c5612bc55d2c4e084da"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Thu Oct 08 21:33:14 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 08 21:33:14 2026 -0300"
      },
      "message": "Merge pull request #206 from apache/OPENJPA-2980\n\n[OPENJPA-2980] Replay a criteria query registered by addNamedQuery as a criteria query"
    },
    {
      "commit": "b09ee3e2f6bd0fcaddd275cf3c76024d4f304e04",
      "tree": "e7d497fc6d09c8ea6a7398a0c71eff5b0a2729f4",
      "parents": [
        "de937d318c8f3a1a19d11e699c246625bc9d6269",
        "67c6a78ebe8abb7a25715f00597d6b05d2d6c4ee"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Thu Oct 08 21:30:21 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 08 21:30:21 2026 -0300"
      },
      "message": "Merge pull request #205 from apache/OPENJPA-2952\n\n[OPENJPA-2952] Require evidence of persistence before assuming detached"
    },
    {
      "commit": "de937d318c8f3a1a19d11e699c246625bc9d6269",
      "tree": "f378b13197e801811a44b76dcfcc6ebf9aa5230f",
      "parents": [
        "d268697fe86e6b8339e58a16581f96891a8761d6"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "13417392+rzo1@users.noreply.github.com",
        "time": "Thu Oct 08 17:32:40 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 08 22:32:40 2026 +0700"
      },
      "message": "[OPENJPA-3010] Assert the bulk delete and map key SQL per dictionary (#207)\n\nThe tests added with the owned table cleanup and the map key column option\nasserted the shape Derby and H2 emit. MySQL and MariaDB render an unqualified\nbulk delete as \"DELETE t0 FROM T t0\" rather than \"DELETE FROM T\", so the\nassertions now accept an alias on either side of the FROM. The legacy map key\ncolumn name is spelled differently again by every dictionary - KEY where the\nword is legal, KEY0 where it is renamed and a delimited key where it is quoted\ninstead - so that assertion now compares the generated DDL without delimiters\nand without case instead of expecting one spelling.\n\nReported by Maxim Solodovnik, who runs the MySQL suite by hand; the GitHub\nActions matrix covers only Derby and H2, so no pull request exercises the\nother dictionaries."
    },
    {
      "commit": "1f919c3297525215d18db1bbe86e8c8403ae4325",
      "tree": "4adfa2c03cf6a6f19a1d7940bebbadb487f86c88",
      "parents": [
        "b4bfa57f0c03f07a2c3053ff9a9820ec94471ae9"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Thu Oct 08 13:20:35 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Thu Oct 08 17:30:44 2026 +0200"
      },
      "message": "[OPENJPA-3009] Make a JPQL LIKE without ESCAPE mean the same on every database\n\nJakarta Persistence gives a LIKE pattern without an ESCAPE clause no escape\ncharacter at all, so a backslash in it is an ordinary character. H2, MySQL,\nMariaDB and PostgreSQL default their LIKE to a backslash escape, so the same\nquery matched only on Derby.\n\nOpenJPA already added an ESCAPE clause for a dictionary with\nrequiresSearchStringEscapeForLike, but filled it with the dictionary escape\ncharacter, which gave that character an escape meaning the query never asked\nfor. Write an explicit \"no escape character\" clause instead, and set the flag\nfor H2, whose LIKE has the same default. The expression used for it is the new\ndictionary setting searchStringNoEscape, because the databases do not spell it\nalike: \u0027\u0027 is a non-standard spelling which H2 and PostgreSQL accept, MySQL\naccepts it only while sql_mode has no NO_BACKSLASH_ESCAPES and rejects it with\n\"Incorrect arguments to ESCAPE\" otherwise, MariaDB 11.4 and 11.8 ignore it\naltogether and keep their backslash escape, and a standard conforming database\nsuch as Derby rejects it because the standard wants exactly one character. Both\nmysql family dictionaries therefore use CHAR(0), which behaves as no escape\ncharacter for every pattern without a NUL character and works in either\nsql_mode, and a dictionary which turns the flag on has to supply a value its\nown database accepts.\n\nAn ESCAPE clause which names the empty string is the same statement that there\nis no escape character, so both the generated SQL and the in-memory evaluation\nnow treat it like a missing clause instead of passing \u0027\u0027 through to the\ndatabase, which Derby rejects outright.\n\nThe pattern itself is passed through untouched, so the generated SQL still does\nnot depend on the pattern value and a parameterized LIKE stays eligible for the\nprepared query cache. A query supplied ESCAPE clause keeps working unchanged,\nand the in-memory Matches evaluation already treats a backslash literally, so\nboth paths now agree. A query supplied backslash escape is rendered from\nsearchStringEscape, which MySQL and MariaDB double, and only accept while\nsql_mode has no NO_BACKSLASH_ESCAPES; the manual now says so for the migration\npath it recommends.\n"
    },
    {
      "commit": "67c6a78ebe8abb7a25715f00597d6b05d2d6c4ee",
      "tree": "67142eac7053cd0c8e24d326c1eea104df3b24c5",
      "parents": [
        "b4bfa57f0c03f07a2c3053ff9a9820ec94471ae9"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Thu Oct 08 11:41:29 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Thu Oct 08 17:29:34 2026 +0200"
      },
      "message": "[OPENJPA-2952] Require evidence of persistence before assuming detached\n\nThe pre-flush check for a relation without cascade treated every\nunmanageable instance of a known entity type as detached, without any\nevidence that the instance had ever been persisted. The case it was\nwritten for does not need it: an instance of a runtime enhanced\n(subclassed) entity type is manageable, so it goes through the state\nmanager branch below, which confirms the detached state. Drop the block\nso that a truly transient instance is reported again.\n\nThe datastore probe in that branch ran for every manageable instance\nwithout a state manager, even when the identity of the instance alone\nsettles the question. Read the primary key values off the instance and\nskip the lookup if they show that no identity was ever assigned. The\nvalues cannot be taken from the application identity object, because\nthat object represents an unset wrapper or primitive primary key as a\nzero and so cannot be told apart from an identity of zero, which is how\na flush could probe for and accept a record that has nothing to do with\nthe instance at hand. A primary key field with a value strategy still\nholding the default value of its type counts as unset as well, which is\nhow OpenJPA reads it when it decides to generate a value; a non-default\nversion field is evidence of a store record and keeps the lookup.\n\nThe probe runs irrespective of the Compatibility property\nCheckDatabaseForCascadePersistToDetachedEntity, because for an instance\nwithout persistence state in the current context it is the only\navailable evidence. Say so in the migration considerations, where that\nproperty is described.\n"
    },
    {
      "commit": "d268697fe86e6b8339e58a16581f96891a8761d6",
      "tree": "fb9f59e8134d930b3af858ddd207e89cd47f67c4",
      "parents": [
        "dcac971d4330d94958f14041ab13a8b1235408f3"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "13417392+rzo1@users.noreply.github.com",
        "time": "Thu Oct 08 16:39:48 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 08 21:39:48 2026 +0700"
      },
      "message": "[OPENJPA-3008] Keep the H2 test database open for the test JVM (#203)\n\nH2 closes the file database whenever the connection pool of a factory drains\nto zero, which the suite does once per EntityManagerFactory, and compacts the\nstore on every close. The compaction trips an assertion inside H2, the close\nis abandoned half way through and commits made just before it are lost, so a\nlater test class finds the schema it just created gone. Keep the database open\nfor the lifetime of the test JVM instead."
    },
    {
      "commit": "dcac971d4330d94958f14041ab13a8b1235408f3",
      "tree": "a337b34044efd4a8fa9457885c8b6d1a11afbae5",
      "parents": [
        "b4bfa57f0c03f07a2c3053ff9a9820ec94471ae9"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "13417392+rzo1@users.noreply.github.com",
        "time": "Thu Oct 08 16:38:19 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 08 21:38:19 2026 +0700"
      },
      "message": "[OPENJPA-2946] Address the JavaCC warnings in the JPQL grammar build (#204)\n\nTwo independent concerns:\n\n(1) The javacc-maven-plugin execution passed -JDK_VERSION\u003d17 (from\n${java.class.version}, which holds the compiler release, not a class file\nversion) to both jjtree and javacc, and both answered \u0027Bad option value in\n\"-JDK_VERSION\u003d17\" will be ignored.\u0027. JavaCC 5.0 types a command line option\nvalue by the class of its default, so a value that parses as an integer is\nrejected for the String option JDK_VERSION and discarded; the build has\ntherefore always generated with the default 1.5. Every JDK dependent switch\nin JavaCC 5.0 is jdkVersionAtLeast(1.5), so no accepted value could change\nthe output - generating with and without the option yields byte identical\nsources. The option is dropped rather than re-spelled.\n\n(2) arithmetic_expression() and arithmetic_term() eliminated left recursion\nby recursing on themselves inside a (...)* loop, which made the choice in the\nloop ambiguous (\u0027Choice conflict in (...)* construct ... common prefixes, one\nof which is: \"+\"\u0027 / \u0027\"*\"\u0027) and, because JavaCC resolves such a conflict\ngreedily in favour of the nested expansion, parsed a - b - c as a - (b - c)\nand a / b / c as a / (b / c). Both productions now iterate over the operator\nand recurse one level down, which removes the conflict and makes the\noperators left associative as the specification requires. Additive and\nmultiplicative precedence is unchanged.\n\norderby_item() also had two \u0027Choice conflict involving two expansions\u0027\nwarnings, for orderby_extension() and identification_variable() against the\nlater scalar_expression() alternative. JavaCC\u0027s default already picks the\nearlier alternative, which is the intended parse, so both are annotated with\nLOOKAHEAD(1) to state that the one token decision is intended. A syntactic\nLOOKAHEAD would have made every alternative of the choice explicit, which stops\nJavaCC from emitting the token set switch for it: the expected token set of a\nmalformed ORDER BY item would then be empty and the reported offset would move\nto the start of the item, degrading the user visible jpql-parse-error message.\n\nThe grammar build now emits no warnings at all.\n\nThe associativity change alters the result of existing queries, so it is\ndocumented in the 4.2.0 incompatibilities and the operator precedence section\nof the manual gains an explicit note on evaluation order."
    },
    {
      "commit": "00064aa235e2702e6dc57c5612bc55d2c4e084da",
      "tree": "ebd1ad0b5edfeb0a327f1ade07c65a0a2bb4b7c0",
      "parents": [
        "db8aec7d561620cad87fea8f7ad369d992cfcea9"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Mon Oct 05 19:56:52 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Thu Oct 08 12:20:36 2026 +0200"
      },
      "message": "[OPENJPA-2980] Replay a criteria query registered by addNamedQuery as a criteria query\n\naddNamedQuery() re-labelled a criteria query as JPQL and stored the CQL\nrendering of the CriteriaQuery as the query string. That rendering is not\nguaranteed to be parseable JPQL: string literals are not escaped and\nsubqueries are not parenthesized, so createNamedQuery() either failed to\nparse the query or recreated a different one.\n\nKeep the compiled criteria form in the QueryMetaData instead and replay it\nin createNamedQuery(), so a criteria query is recreated as a criteria query.\nFor that to survive, ExpressionStoreQuery now retains the parsed form handed\nto setQuery() and reuses it when the query has no string to parse again,\ne.g. after setResultClass() invalidated the compilation.\n\nThe query is compiled before its metadata is captured: the candidate and the\nresult type of a query are only known once it has been compiled, and a criteria\nquery has no query string they could be recovered from afterwards, so capturing\nthem from an uncompiled query left both of them null and the registered query\nwas invisible to getNamedQueries(Class) - unlike a JPQL one, which the facade\ncompiles before addNamedQuery() sees it. The identifier of the query, the CQL\nrendering of its tree, is rendered there as well, while the registering thread\nis still the only one holding the tree; createNamedQuery() reuses it instead of\nrendering the shared tree on every replay.\n\nA named query is an EntityManagerFactory-wide artefact, so the retained\ncriteria tree is now replayed by every EntityManager. Translating a criteria\ntree to a kernel expression tree mutates the tree - the alias, variable and\nvalue maps are re-populated and a subquery records the kernel subquery it was\ntranslated to - so concurrent replays corrupted each other, yielding wrong\nresults, malformed SQL or a ConcurrentModificationException. The tree itself\nis not a usable monitor for that: a snapshot deliberately shares those\nmutable maps with the original query and with every other snapshot, and the\ncaptive query of a subquery shares the parameter map of the query it belongs\nto, so locking on the object being translated still lets two snapshots of one\ntree race. Each tree therefore carries a TranslationLock, created by the root\nquery and handed to every snapshot of it and to every subquery delegate, and\nthe translation is serialized on that lock. A set operation translates two\nindependent trees and takes both their locks, in a fixed order so that two set\noperations over the same operands cannot deadlock.\n\nThe replayed query is identified by the CQL rendering of its tree, which is\nnot a query string it can be parsed from, so the prepared query cache must not\nhold it: it only excluded LANG_SQL and LANG_METHODQL, and a criteria query\nthat had been cached under that rendering was rebuilt by parsing the rendering\nas JPQL as soon as something made a later execution abandon the cached entry,\ne.g. setting a lock mode. Name the criteria language in QueryLanguages and\nexclude it from the cache.\n\nExcluding it from the cache only covers the write side. The rendering of a\nsimple criteria query is valid JPQL, so an unrelated JPQL query of exactly that\ntext can be cached under the identifier of the criteria query, and the facade\nlooked the cache up by that identifier alone: a replay that abandoned the cached\nentry - with a lock mode, or with a null parameter value - then rebuilt the\ncriteria query by parsing its own identifier as JPQL, which silently discarded\nthe criteria tree or failed outright with \"declared parameters were not given\nvalues\". Rebuilding from the identifier now happens for JPQL queries only.\n\nAlso narrow the exception handling in addNamedQuery(): getFlushMode() and\ngetMaxResults() do not fail for any query a facade query can wrap, and only\ngetLockMode() is specified to throw IllegalStateException for non-SELECT or\nnative queries, so genuine failures are no longer swallowed.\n\nUpdate the 4.2.0 migration notes, which still described the removed\n\"stored as JPQL text\" behaviour.\n"
    },
    {
      "commit": "b4bfa57f0c03f07a2c3053ff9a9820ec94471ae9",
      "tree": "20d2a472609dbed3e293f14ab10bba267d1dd7ca",
      "parents": [
        "1f127c7ab15ef5a04a6013eeadcba66adb4e6b1f",
        "79ad92094e16fa033179bc88aa090859b285659a"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Tue Oct 06 08:08:22 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 06 08:08:22 2026 -0300"
      },
      "message": "Merge pull request #201 from apache/OPENJPA-2973\n\n[OPENJPA-2973] Consult the AttributeConverter for null values"
    },
    {
      "commit": "1f127c7ab15ef5a04a6013eeadcba66adb4e6b1f",
      "tree": "7533d6eb702a84968595cf57d3636ba916a3a06e",
      "parents": [
        "911485b3ca86f83c138b468168434bbc520fa05f",
        "c6e60b5ded27a24d25eaffd671559f2391fe7bd2"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Tue Oct 06 06:30:13 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 06 06:30:13 2026 -0300"
      },
      "message": "Merge pull request #202 from apache/OPENJPA-2988\n\n[OPENJPA-2988] tautology in query is removed"
    },
    {
      "commit": "911485b3ca86f83c138b468168434bbc520fa05f",
      "tree": "e8e219e94d256aaf8f384be0c21aa817e35980c3",
      "parents": [
        "85132b22d83a9e0728b2d1b7bc17add084db9124",
        "fcc923bb3601a8d2374d62a76094b99d2e3c4d1f"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Tue Oct 06 06:29:29 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 06 06:29:29 2026 -0300"
      },
      "message": "Merge pull request #200 from apache/OPENJPA-2953\n\n[OPENJPA-2953] Keep converter overrides out of shared embeddable and superclass meta"
    },
    {
      "commit": "85132b22d83a9e0728b2d1b7bc17add084db9124",
      "tree": "fdc3e53ea3d36a9c383f066b296fd9579f876bb2",
      "parents": [
        "db8aec7d561620cad87fea8f7ad369d992cfcea9",
        "db0926b2237e331d146a9632cc0f8a65898c22f1"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Tue Oct 06 06:27:15 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 06 06:27:15 2026 -0300"
      },
      "message": "Merge pull request #199 from apache/OPENJPA-2965\n\n[OPENJPA-2965] Pin the bulk delete of a candidate with cascade delete fields"
    },
    {
      "commit": "c6e60b5ded27a24d25eaffd671559f2391fe7bd2",
      "tree": "2a003ee062838c357a2e48085d33f52e884b0101",
      "parents": [
        "db8aec7d561620cad87fea8f7ad369d992cfcea9"
      ],
      "author": {
        "name": "Maxim Solodovnik",
        "email": "solomax@apache.org",
        "time": "Tue Oct 06 14:06:11 2026 +0700"
      },
      "committer": {
        "name": "Maxim Solodovnik",
        "email": "solomax@apache.org",
        "time": "Tue Oct 06 14:06:11 2026 +0700"
      },
      "message": "[OPENJPA-2988] tautology in query is removed\n"
    },
    {
      "commit": "79ad92094e16fa033179bc88aa090859b285659a",
      "tree": "e56f8fe29b9a2b42f08269d3142f6cd7b1712276",
      "parents": [
        "db8aec7d561620cad87fea8f7ad369d992cfcea9"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Mon Oct 05 19:43:16 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Mon Oct 05 20:20:13 2026 +0200"
      },
      "message": "[OPENJPA-2973] Consult the AttributeConverter for null values\n\nA converter may legitimately map null to a column or attribute default,\nso drop the val \u003d\u003d null short-circuits in the externalization path. A\nnull returned by the converter still stores/reads a null column value.\n\nCollection and map fields keep converting their elements through\nConverterElementHandler, so the new guard mirrors isExternalized().\nArrays stay on the whole-value path, matching the same collection/map\ntest that MappingRepository applies before its array handling.\n\nQueries are left alone: a null in a query means SQL NULL and is not\npassed through the converter, so \"x IS NULL\", \"x \u003d :nullParam\",\n\"SET x \u003d NULL\" and \"SET x \u003d :nullParam\" keep one meaning between them.\n\nA RuntimeException from a converter is still wrapped in a StoreException,\nbut with the localized converter-err message, so the failure names the\nfield and the offending value instead of only the converter\u0027s own text.\n\nDocument why the converter is invoked reflectively (openjpa-kernel does\nnot depend on jakarta.persistence-api) and that there is no container\nhook for CDI-managed converters, and note the incompatibility in the\n4.2.0 migration considerations.\n\nThe test converters are made null-safe, as the specification requires of\na converter, and the null shapes they cover - an array attribute with an\nauto-applied converter, a converted attribute of an embeddable and an\nabsent embeddable - are pinned by tests.\n"
    },
    {
      "commit": "fcc923bb3601a8d2374d62a76094b99d2e3c4d1f",
      "tree": "5e34d3ee836cfa5f908fdcd75e6045cca2c48aec",
      "parents": [
        "db8aec7d561620cad87fea8f7ad369d992cfcea9"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Mon Oct 05 19:40:41 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Mon Oct 05 20:05:06 2026 +0200"
      },
      "message": "[OPENJPA-2953] Keep converter overrides out of shared embeddable and superclass meta\n\npropagateEmbeddedConverters() set the converter both on the per-embedding\nembedded metadata copy and on the repository-level ClassMetaData of the\nembeddable type. The latter is shared by every entity embedding that\nembeddable, so a @Convert(attributeName\u003d...) declared by one entity leaked\ninto all other embeddings (last resolved wins). Only the per-embedding copy\nis updated now. A converter declared on the embeddable\u0027s own attribute is\nunaffected and still applies everywhere.\n\nA class-level @Convert(attributeName\u003d...) for an attribute inherited from a\nMappedSuperclass leaked the same way: the override was written to the field\nmetadata owned by the superclass, which getFields() splices into every\nsibling subclass. The override is applied to the subclass\u0027 own redefinition\nof the inherited field now, after defineSuperclassFields() created it.\n\nFor a collection or map of embeddables the embedded metadata hangs off the\nelement resp. key value, not off the field\u0027s value, so such overrides were\ncollected and then silently dropped. All three value slots are considered\nnow, with \"key.\" and \"value.\" addressing a map\u0027s key resp. value.\n"
    },
    {
      "commit": "db0926b2237e331d146a9632cc0f8a65898c22f1",
      "tree": "fdc3e53ea3d36a9c383f066b296fd9579f876bb2",
      "parents": [
        "db8aec7d561620cad87fea8f7ad369d992cfcea9"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Mon Oct 05 19:38:10 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Mon Oct 05 19:56:24 2026 +0200"
      },
      "message": "[OPENJPA-2965] Pin the bulk delete of a candidate with cascade delete fields\n\nRemoving the cascade guard from the JDBC bulk delete strategy no longer\nleaves the rows of the join tables and element collection tables behind: the\ndelete cleans up the tables the candidate owns itself. The guard rejected a\nfield whose own value had a cascade delete, which is what OpenJPA\u0027s\n@Dependent and a to-one cascade\u003dREMOVE set; a collection declares its cascade\non the element value, which the guard never read, so only a single-valued\nrelation ever forced the delete onto the in-memory path, where the owned\ntables were cleaned up as a side effect of removing every instance. Nothing\ncovered that shape, so a regression could pass unnoticed.\n\nThe new test deletes such a candidate - one dependent and one cascade\u003dREMOVE\ndirect relation next to a dependent join table collection, a dependent\nbi-directional one-to-many and an element collection - and asserts that the\njoin table and the element collection table are emptied while the related\nentity rows survive: the targets of the direct relations, the elements of the\njoin table collection and the rows of the one-to-many, whose foreign key\nlives in a table the candidate does not own. A bulk delete does not cascade\n(specification section 4.10), so none of those rows is an owned row.\n\nThe migration note described the previous behaviour for an @ElementCollection\nthe wrong way round. Such a candidate already took the bulk SQL path and its\ncollection table rows were left behind on the deleted keys; removing them is\na fix (OPENJPA-2990), not a replacement for cascading that was lost.\n"
    },
    {
      "commit": "db8aec7d561620cad87fea8f7ad369d992cfcea9",
      "tree": "376114b0207c2330dc12568aa698cc00411280ea",
      "parents": [
        "4ea05d8a999ec1c4eef2c0a6c2e93727752c22c3"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "13417392+rzo1@users.noreply.github.com",
        "time": "Mon Oct 05 19:30:16 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 05 19:30:16 2026 +0200"
      },
      "message": "[OPENJPA-2949] Document the ID()/VERSION() comparison operators and in-memory set operations (#192)"
    },
    {
      "commit": "4ea05d8a999ec1c4eef2c0a6c2e93727752c22c3",
      "tree": "7dcf0ca9dd1d9b73b6432812e69692c9e2692817",
      "parents": [
        "127273d1bc891442085f87f15e742beda457620d",
        "c380948ca9742155413bf4cdf66abbecd09dbe8d"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Wed Sep 30 21:53:40 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 30 21:53:40 2026 -0300"
      },
      "message": "Merge pull request #198 from apache/OPENJPA-2990\n\n[OPENJPA-2990] Remove the rows of the tables owned by bulk deleted entities"
    },
    {
      "commit": "c380948ca9742155413bf4cdf66abbecd09dbe8d",
      "tree": "7dcf0ca9dd1d9b73b6432812e69692c9e2692817",
      "parents": [
        "31892243d9cdbb915df118fcabfc87c8384242a7"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Wed Sep 30 20:11:15 2026 -0300"
      },
      "committer": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Wed Sep 30 20:11:15 2026 -0300"
      },
      "message": "[OPENJPA-2990] Adding {} for clarity and try-with-resources\n"
    },
    {
      "commit": "31892243d9cdbb915df118fcabfc87c8384242a7",
      "tree": "09e3f22b28405835c61117b21278b1314c609b73",
      "parents": [
        "a6ff4483ed492114125f32d09c68d6d832ae9854",
        "127273d1bc891442085f87f15e742beda457620d"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Wed Sep 30 17:27:37 2026 -0300"
      },
      "committer": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Wed Sep 30 17:27:37 2026 -0300"
      },
      "message": "Merge branch \u0027master\u0027 into OPENJPA-2990\n"
    },
    {
      "commit": "127273d1bc891442085f87f15e742beda457620d",
      "tree": "30570e099cae02b452df7da12a4115ecf5067504",
      "parents": [
        "cf36da3e6af55fb1477013bda161e2da20bf53ad",
        "e0b008952889fb24bc3829738af8d78873170b7d"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Wed Sep 30 16:00:45 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 30 16:00:45 2026 -0300"
      },
      "message": "Merge pull request #197 from apache/OPENJPA-2994\n\n[OPENJPA-2994] Add compatibility option for the default map key column name"
    },
    {
      "commit": "e0b008952889fb24bc3829738af8d78873170b7d",
      "tree": "c7367cf267246fa9b4a56167ddfd1fdee15d6c1d",
      "parents": [
        "57e7ee3efd9834f3342181e4084f8f1b983b17ae"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Wed Sep 30 14:32:58 2026 -0300"
      },
      "committer": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Wed Sep 30 14:32:58 2026 -0300"
      },
      "message": "[OPENJPA-2994] Added try-with-resource in test\n"
    },
    {
      "commit": "cf36da3e6af55fb1477013bda161e2da20bf53ad",
      "tree": "7f3c2ebd191e53aa6ca8eb58f97e1e2dd5d72e31",
      "parents": [
        "d5a3d3195a5b0cfc6d094af5cdc41ada275ab34d",
        "f15bcbe476f07e93889f88d73d8482c3219d4878"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Wed Sep 30 13:32:23 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 30 13:32:23 2026 -0300"
      },
      "message": "Merge pull request #194 from apache/OPENJPA-2975\n\n[OPENJPA-2975] Narrow criteria TREAT joins instead of casting silently"
    },
    {
      "commit": "f15bcbe476f07e93889f88d73d8482c3219d4878",
      "tree": "ce0ddcea0c8a76fda5eee07de08d59b8ca025a26",
      "parents": [
        "052a973cdd28efdfddb4d8e35211e032e39b89c7"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Wed Sep 30 12:05:03 2026 -0300"
      },
      "committer": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Wed Sep 30 12:05:03 2026 -0300"
      },
      "message": "[OPENJPA-2975] Fixing vargars warnings\n"
    },
    {
      "commit": "d5a3d3195a5b0cfc6d094af5cdc41ada275ab34d",
      "tree": "e2a83e76f7d160c8fb4f36f079bfde37924596b7",
      "parents": [
        "393a48cc6f6f9bd03beaf1873b4b53eba94a6994",
        "af41139bc85a07a2913559d39b1d0c54d31b3178"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Mon Sep 28 10:31:14 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 28 10:31:14 2026 -0300"
      },
      "message": "Merge pull request #196 from apache/OPENJPA-2989\n\n[OPENJPA-2989] Add a compatibility option to restore lazy query result lists"
    },
    {
      "commit": "af41139bc85a07a2913559d39b1d0c54d31b3178",
      "tree": "e2a83e76f7d160c8fb4f36f079bfde37924596b7",
      "parents": [
        "e034fc1bd4a03c083b07d539ddd6bf0a8aad142f"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Mon Sep 28 09:42:38 2026 -0300"
      },
      "committer": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Mon Sep 28 09:42:38 2026 -0300"
      },
      "message": "[OPENJPA-2989] Fixes error made when merging master into branch\n"
    },
    {
      "commit": "e034fc1bd4a03c083b07d539ddd6bf0a8aad142f",
      "tree": "e61dc811571afd7239c01f8a4ed7d8fb04e5a5a5",
      "parents": [
        "237123ad87396015a97641ff6a0987ef26ffa534",
        "393a48cc6f6f9bd03beaf1873b4b53eba94a6994"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Mon Sep 28 08:15:47 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 28 08:15:47 2026 -0300"
      },
      "message": "Merge branch \u0027master\u0027 into OPENJPA-2989"
    },
    {
      "commit": "393a48cc6f6f9bd03beaf1873b4b53eba94a6994",
      "tree": "862850c38953d35ec122fb6ba28f2323b8d8f07a",
      "parents": [
        "ee1e4acc178e7d4a07369f0d43475f4a810ac592",
        "560121f926953acb178a963fb0cf644a1ac4bcb0"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Mon Sep 28 08:12:27 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 28 08:12:27 2026 -0300"
      },
      "message": "Merge pull request #195 from apache/OPENJPA-2991\n\n[OPENJPA-2991] Gate the nested compound selection rejection behind a compatibility option"
    },
    {
      "commit": "ee1e4acc178e7d4a07369f0d43475f4a810ac592",
      "tree": "811a197f638042ab84ba271f3784d10ba6812359",
      "parents": [
        "0e8b4abfb04d02d9bf9a862b14b8afadc88f3445",
        "cf3808f2ac092904f530fd0d09716aa398d4df96"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Mon Sep 28 08:05:36 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 28 08:05:36 2026 -0300"
      },
      "message": "Merge pull request #184 from apache/OPENJPA-2970\n\n[OPENJPA-2970] Let an explicit null named parameter win over positional lookup"
    },
    {
      "commit": "0e8b4abfb04d02d9bf9a862b14b8afadc88f3445",
      "tree": "ff4e43a2152b76d2024b0357c8b805b38fe3ed16",
      "parents": [
        "3ec80476edc500906efec42e8d3b543399170e3b"
      ],
      "author": {
        "name": "Maxim Solodovnik",
        "email": "solomax@apache.org",
        "time": "Mon Sep 28 12:55:28 2026 +0700"
      },
      "committer": {
        "name": "Maxim Solodovnik",
        "email": "solomax@apache.org",
        "time": "Mon Sep 28 12:55:28 2026 +0700"
      },
      "message": "[OPENJPA-3003] build is fixed to work with new shurefire plugin\n"
    },
    {
      "commit": "3ec80476edc500906efec42e8d3b543399170e3b",
      "tree": "cb11d7a0cd577e482b19450fde0b43790e1bbba1",
      "parents": [
        "43e2335ee4ae58325fb7b3b43378afab60972001"
      ],
      "author": {
        "name": "Maxim Solodovnik",
        "email": "solomax666@gmail.com",
        "time": "Mon Sep 28 10:44:45 2026 +0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 28 10:44:45 2026 +0700"
      },
      "message": "[OPENJPA-3003] ASF parent and slf4j are updated"
    },
    {
      "commit": "a6ff4483ed492114125f32d09c68d6d832ae9854",
      "tree": "a131a5d5405974073b0d02a45b66e02fa431c9cb",
      "parents": [
        "43e2335ee4ae58325fb7b3b43378afab60972001"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Sat Sep 26 21:30:16 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Sun Sep 27 07:47:54 2026 +0200"
      },
      "message": "[OPENJPA-2990] Remove the rows of the tables owned by bulk deleted entities\n\nA bulk delete does not cascade to related entities, but the rows of the join\ntables and element collection tables owned by the deleted entities are not\nentities themselves. Since the cascade guard was removed from the JDBC bulk\ndelete strategy they were left behind, dangling on the primary keys of the\ndeleted rows.\n\nWhen the candidate owns such a table, the delete now evaluates the criteria\nexactly once into a list of primary keys and deletes by those keys: the owned\ntables first, the entity table last. Nothing re-evaluates the criteria against\na database a previous statement has already changed. Candidates with a\ncomposite primary key, or with a join foreign key that is not a single column\nreferencing that primary key, are executed in memory instead. The\ncompatibility option CleanupOwnedTablesOnBulkDelete (default true) suppresses\nthe cleanup.\n\nA delete that carries no criteria at all - no where clause and no\ndiscriminator or subclass condition - matches every candidate row, so every\nrow of every owned table belongs to a deleted candidate. Such a delete skips\nthe key select and empties the owned tables outright, which keeps the single\nstatement delete of a whole table a single statement per table.\n\nThe table of a join foreign key is only taken for an owned table if it is\nneither a table of the key type nor one of the element type or of any of their\njoined superclasses, so an inverse key mapping never turns into a delete of\nentity rows. An embedded value has no table of its own - the table of an\nembeddable is the table it is embedded into - so the collection table of an\nelement collection of embeddables is not mistaken for the table of a related\nentity.\n\nA join foreign key that carries constant columns discriminates the rows of a\ntable that is shared by more than one mapping, so the candidates do not own\nevery row of it: neither the key delete nor the delete without criteria is\napplicable and such a candidate is executed in memory.\n"
    },
    {
      "commit": "57e7ee3efd9834f3342181e4084f8f1b983b17ae",
      "tree": "33ca22b9de5f8d186a7bd0fef563648111de6f6a",
      "parents": [
        "43e2335ee4ae58325fb7b3b43378afab60972001"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Sat Sep 26 19:44:19 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Sat Sep 26 19:50:19 2026 +0200"
      },
      "message": "[OPENJPA-2994] Add compatibility option for the default map key column name\n\nSection 11.1.35 requires the default map key column to be named\n\u003cfield\u003e_KEY, which does not match schemas created by earlier releases\n(where the default was \"key\", usually materialized as \"KEY0\").\n\nGate the default name derivation behind the new compatibility option\nUseSpecDefaultMapKeyColumnName. It defaults to true, so the spec name\nis used out of the box; setting it to false restores the old default.\nAn explicit @MapKeyColumn is unaffected either way.\n"
    },
    {
      "commit": "237123ad87396015a97641ff6a0987ef26ffa534",
      "tree": "f2431988c78f293fe5b0162e1f8d605e7ab2512d",
      "parents": [
        "43e2335ee4ae58325fb7b3b43378afab60972001"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Sat Sep 26 19:43:33 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Sat Sep 26 19:48:26 2026 +0200"
      },
      "message": "[OPENJPA-2989] Add a compatibility option to restore lazy query result lists\n\nQuery.getResultList() copies the kernel ResultList into an ArrayList since\nthe Jakarta Persistence 3.2 work, so the complete result is materialized and\nopenjpa.FetchBatchSize no longer streams rows to the caller. Keep that as the\ndefault and add the MaterializeQueryResultList compatibility option, which\nrestores the lazy ResultList for applications that rely on streaming, and\ndocument the memory implication in the migration considerations.\n"
    },
    {
      "commit": "560121f926953acb178a963fb0cf644a1ac4bcb0",
      "tree": "067a31d7493e50f03e9cb4eefcb214a33291834d",
      "parents": [
        "43e2335ee4ae58325fb7b3b43378afab60972001"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Sat Sep 26 19:41:42 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Sat Sep 26 19:45:33 2026 +0200"
      },
      "message": "[OPENJPA-2991] Gate the nested compound selection rejection behind a compatibility option\n\nRejecting nested tuple/array selections in CriteriaBuilder.tuple()/array()\ndrops an OpenJPA extension that applications may rely on. Keep the\nspecification behaviour as default and add the compatibility option\nAllowNestedCompoundSelection to restore the historic nesting support.\n"
    },
    {
      "commit": "052a973cdd28efdfddb4d8e35211e032e39b89c7",
      "tree": "24b78a317b11e64b4597741fba9c8863f446a0a2",
      "parents": [
        "43e2335ee4ae58325fb7b3b43378afab60972001"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Fri Sep 25 21:50:10 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Fri Sep 25 22:01:30 2026 +0200"
      },
      "message": "[OPENJPA-2975] Narrow criteria TREAT joins instead of casting silently\n\nThe treat(Join/CollectionJoin/SetJoin/ListJoin/MapJoin, Class) overloads\nonly cast their argument, so no type narrowing was applied at all. A\ntreated join now resolves its attributes against the narrowed type and\nbinds its kernel variable to the narrowed metadata, which renders the\nsame discriminator condition as a JPQL TREAT join, including the\nsubclasses of the treated class.\n\nA join that is correlated to an outer query, or that is reached from\nsuch a join, carries no kernel variable of its own, so there is no\nvariable that could carry the narrowed metadata. Such a join is now\nrejected with an UnsupportedOperationException rather than being\nnarrowed without any effect.\n\ntreat(Path, Class) delegates to the Root and Join implementations and\nrejects any other path expression with an UnsupportedOperationException\ninstead of returning it unnarrowed.\n\nThe type restriction of a treated root is evaluated after the projection\nand ordering terms, so that it is applied for a root that is treated in\nthe select clause only, and it now matches the subclasses of the treated\nclass as well.\n"
    },
    {
      "commit": "43e2335ee4ae58325fb7b3b43378afab60972001",
      "tree": "61e3938ec1143d3220c4c6b3854002fd36b8fc22",
      "parents": [
        "94d34574543398a53d5b0e9b58b227f4c4720b6d",
        "e34199898d5a19e2c043778a5902ddfca232061f"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "pcristof@gmail.com",
        "time": "Thu Sep 17 21:28:30 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 17 21:28:30 2026 -0300"
      },
      "message": "Merge pull request #187 from apache/OPENJPA-2977-no-persistence-xml-resource\n\n[OPENJPA-2977] Drop the unrecognized openjpa.noPersistenceXMLResource property\n"
    },
    {
      "commit": "e34199898d5a19e2c043778a5902ddfca232061f",
      "tree": "61e3938ec1143d3220c4c6b3854002fd36b8fc22",
      "parents": [
        "f8dcbfedc11c8aecd875bb86581d629eb900c146"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Thu Sep 17 19:35:18 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 17 20:48:51 2026 -0300"
      },
      "message": "[OPENJPA-2977] Fix merge conflicts\n"
    },
    {
      "commit": "f8dcbfedc11c8aecd875bb86581d629eb900c146",
      "tree": "61e3938ec1143d3220c4c6b3854002fd36b8fc22",
      "parents": [
        "fa7ea9af98d7ffff00980427bbb05b7f3dd97cd1",
        "94d34574543398a53d5b0e9b58b227f4c4720b6d"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Thu Sep 17 19:35:18 2026 -0300"
      },
      "committer": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Thu Sep 17 19:35:18 2026 -0300"
      },
      "message": "[OPENJPA-2977] Fix merge conflicts\n"
    },
    {
      "commit": "94d34574543398a53d5b0e9b58b227f4c4720b6d",
      "tree": "a9dfc5a559ad3fb6a269df88490e5dfc38fc14db",
      "parents": [
        "9659240cc0af3354819a66b092fd848883a45af3"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "13417392+rzo1@users.noreply.github.com",
        "time": "Wed Sep 16 05:49:06 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 16 10:49:06 2026 +0700"
      },
      "message": "[OPENJPA-2961] Include subclasses of the treated class in the TREAT discriminator filter (#189)\n\n* [OPENJPA-2961] Include subclasses of the treated class in the TREAT discriminator filter\n\nBuild the TREAT condition through the discriminator strategy\u0027s class\nconditions, so that subclasses of the treated type are matched with an IN\nover their discriminator values.\n\n* [OPENJPA-2961] Use try-with-resources for the EntityManager in the TREAT subclass test\n\n* [OPENJPA-2961] Restrict a predicate over a TREAT path to the treated type\n\nA TREAT(x AS Type) path in a WHERE clause only overrode the metadata of the\npath, so rows of other types matched a predicate on an attribute they share\nwith the treated type. As defined by the specification, such a predicate is\nnow false if x is not an instance of Type or one of its subclasses. The\nrestriction is added to the predicate containing the TREAT path, so other\nbranches of an OR are not affected.\n\n* [openjpa-2961] Adds other tests on TREAT impl\n\n* [openjpa-2961] Adds header to test entity\n\n* Tab/Space mixture is fixed\n\n---------\n\nCo-authored-by: Paulo Cristovão de Araújo Silva Filho \u003cpcristof@gmail.com\u003e\nCo-authored-by: Maxim Solodovnik \u003csolomax666@gmail.com\u003e"
    },
    {
      "commit": "9659240cc0af3354819a66b092fd848883a45af3",
      "tree": "e626ac51cda9db7cad6a5547876377bb824c124d",
      "parents": [
        "882d23963ba5bd6844345914aae0e309d8dacb63",
        "2f0c9165813a5002600450f239324354b6a83e4c"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Tue Sep 15 17:58:43 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 15 17:58:43 2026 -0300"
      },
      "message": "Merge pull request #183 from apache/OPENJPA-2996\n\n[OPENJPA-2996] Exercise the lazy not-loaded path in load state tests"
    },
    {
      "commit": "882d23963ba5bd6844345914aae0e309d8dacb63",
      "tree": "7e9cfb789e78e7a29e52c691db3f5fc8a2eec0ba",
      "parents": [
        "e81fbc0002f270551508a0273dd217cb18b46a3c",
        "fa4302ce213e4ca6728272840219372d6781a1b6"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Tue Sep 15 17:57:10 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 15 17:57:10 2026 -0300"
      },
      "message": "Merge pull request #185 from apache/OPENJPA-2954\n\n[OPENJPA-2954] Publish the cached AttributeConverter instance safely"
    },
    {
      "commit": "e81fbc0002f270551508a0273dd217cb18b46a3c",
      "tree": "c6f484e48cbf617945aabe7eb59f76c484b6c71b",
      "parents": [
        "830a0b41c1642f3fc1c01db2baead3df818e2ce2",
        "b5e6d26c07dbbdf728f80d6491333c6cc668b7bf"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Tue Sep 15 17:55:34 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 15 17:55:34 2026 -0300"
      },
      "message": "Merge pull request #188 from apache/OPENJPA-2979\n\n[OPENJPA-2979] Support composite ids in getReference(entity)"
    },
    {
      "commit": "830a0b41c1642f3fc1c01db2baead3df818e2ce2",
      "tree": "619b613f36b774de9d952901546d5c5cf83975b6",
      "parents": [
        "d559b21083753dc2b71690cbf519ce618262274a",
        "1dcf7bea23ee3ff3f2c00122228ec8c80b1cb6da"
      ],
      "author": {
        "name": "Paulo Cristovão de Araújo Silva Filho",
        "email": "pcristof@gmail.com",
        "time": "Tue Sep 15 17:53:36 2026 -0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 15 17:53:36 2026 -0300"
      },
      "message": "Merge pull request #190 from apache/OPENJPA-3005\n\n[OPENJPA-3005] Use jakarta.persistence.PersistenceUnitTransactionType internally"
    },
    {
      "commit": "1dcf7bea23ee3ff3f2c00122228ec8c80b1cb6da",
      "tree": "619b613f36b774de9d952901546d5c5cf83975b6",
      "parents": [
        "d559b21083753dc2b71690cbf519ce618262274a"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Tue Sep 15 10:59:55 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Tue Sep 15 10:59:55 2026 +0200"
      },
      "message": "[OPENJPA-3005] Use jakarta.persistence.PersistenceUnitTransactionType internally\n\nPersistenceUnitInfoImpl keeps the transaction type as the non-deprecated\njakarta.persistence.PersistenceUnitTransactionType and only converts to the\nSPI enum in getTransactionType(), which PersistenceUnitInfo still requires in\nJakarta Persistence 3.2. A deprecated setter taking the SPI enum is kept.\n\nThe jakarta.persistence.transactionType property now accepts both enums, a\njakarta.persistence.PersistenceUnitTransactionType value was silently turned\ninto a null transaction type before.\n"
    },
    {
      "commit": "fa7ea9af98d7ffff00980427bbb05b7f3dd97cd1",
      "tree": "951f9f63de8736f3a25074bb3d4ab37cd60780a7",
      "parents": [
        "03285dab900a74e886d79ed4035611cfe5edd652"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Mon Sep 14 20:25:41 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Tue Sep 15 10:51:06 2026 +0200"
      },
      "message": "[OPENJPA-2977] Drop the unrecognized openjpa.noPersistenceXMLResource property\n"
    },
    {
      "commit": "03285dab900a74e886d79ed4035611cfe5edd652",
      "tree": "8436e4448d9527ab3aff6bfb1c5af4c9407a38dc",
      "parents": [
        "d559b21083753dc2b71690cbf519ce618262274a"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Mon Sep 14 20:18:59 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Mon Sep 14 20:24:31 2026 +0200"
      },
      "message": "[OPENJPA-2977] Stop mutating PersistenceConfiguration and honour mapping files\n\nconvert() no longer writes into the caller\u0027s configuration. The derived\nOpenJPA properties are returned by toProperties() on a copy of the\nconfiguration properties, the managed classes and mapping files are wired\ninto the persistence unit info, and a user supplied MetaDataFactory is\nmerged as a proper plugin string. Drop the unused\nPersistenceProductDerivation.load(PersistenceConfiguration, Map).\n"
    },
    {
      "commit": "b5e6d26c07dbbdf728f80d6491333c6cc668b7bf",
      "tree": "75a6c16dc80e81ff495b628fb9fbab792665c5ab",
      "parents": [
        "d559b21083753dc2b71690cbf519ce618262274a"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Mon Sep 14 20:21:38 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Mon Sep 14 20:21:38 2026 +0200"
      },
      "message": "[OPENJPA-2979] Support composite ids in getReference(entity)\n\nDerive the object id from the instance\u0027s state manager or its primary\nkey fields instead of reading a single id field, resolve metadata for\ngenerated subclasses and fail with a clear message when no id is set.\n"
    },
    {
      "commit": "cf3808f2ac092904f530fd0d09716aa398d4df96",
      "tree": "a2b81605b21a4b816581fee50db7fabcf7aacb13",
      "parents": [
        "d559b21083753dc2b71690cbf519ce618262274a"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Mon Sep 14 20:03:10 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Mon Sep 14 20:10:37 2026 +0200"
      },
      "message": "[OPENJPA-2970] Let an explicit null named parameter win over positional lookup\n\nLook stored procedure parameters up with containsKey so a parameter bound\nto null is not replaced by the value registered under its position. Index\nthe parameter array by the parameter position so IN parameters following\nan OUT parameter are bound instead of being silently skipped.\n"
    },
    {
      "commit": "fa4302ce213e4ca6728272840219372d6781a1b6",
      "tree": "caab67716928e24842de963364a307da75f5f00f",
      "parents": [
        "d559b21083753dc2b71690cbf519ce618262274a"
      ],
      "author": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Mon Sep 14 20:03:28 2026 +0200"
      },
      "committer": {
        "name": "Richard Zowalla",
        "email": "rzo1@apache.org",
        "time": "Mon Sep 14 20:06:51 2026 +0200"
      },
      "message": "[OPENJPA-2954] Publish the cached AttributeConverter instance safely\n\nFieldMetaData and ConverterElementHandler are shared across brokers and\nthreads. Make the lazily populated converter caches volatile and create\nthe converter instance with double-checked locking so exactly one\ninstance is published. Document that converter instances are shared and\nmust be thread-safe.\n"
    }
  ],
  "next": "2f0c9165813a5002600450f239324354b6a83e4c"
}
