Compare commits
1897
Commits
rel_1_0_18
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8acbc2624f | ||
|
|
8eaccf16ac | ||
|
|
e209df356a | ||
|
|
4aadcca993 | ||
|
|
25fc9562f0 | ||
|
|
16411cd8d6 | ||
|
|
f7d2556cd3 | ||
|
|
cbc31716c2 | ||
|
|
d514c032cd | ||
|
|
7b0dfe3c46 | ||
|
|
312d529dbb | ||
|
|
e6d0963040 | ||
|
|
2160b7e652 | ||
|
|
db212bcf49 | ||
|
|
0137b75136 | ||
|
|
203de6946e | ||
|
|
b78f460465 | ||
|
|
cb968b6dcd | ||
|
|
2a2011389a | ||
|
|
201c4a60e4 | ||
|
|
66373c5811 | ||
|
|
62bc03c51b | ||
|
|
5c4b556c7a | ||
|
|
837d964004 | ||
|
|
cfaf830a6f | ||
|
|
4f62c23cf3 | ||
|
|
740bb50c22 | ||
|
|
8eda38e2aa | ||
|
|
b9d9d41691 | ||
|
|
f24659b72b | ||
|
|
9268c320bf | ||
|
|
a690ec0824 | ||
|
|
358a0dcf10 | ||
|
|
dc48ac5489 | ||
|
|
53c7fc4690 | ||
|
|
0cdc89c276 | ||
|
|
40401d7933 | ||
|
|
eed102f465 | ||
|
|
4ca3092c0a | ||
|
|
0a1c640531 | ||
|
|
8f318692d4 | ||
|
|
c89a93e953 | ||
|
|
7a4c40ff6b | ||
|
|
d879bed878 | ||
|
|
a3135c494e | ||
|
|
d71f34cb2a | ||
|
|
5fe9da55c7 | ||
|
|
c0bd36873b | ||
|
|
11f5ea1f7f | ||
|
|
c1b87bc95d | ||
|
|
4d7ac4be6c | ||
|
|
12dad561a7 | ||
|
|
71d642711d | ||
|
|
5cc5234e0b | ||
|
|
c1f310df44 | ||
|
|
104625941d | ||
|
|
49197c7b36 | ||
|
|
bb7b353d6f | ||
|
|
b2afef966d | ||
|
|
833583458c | ||
|
|
fcb5dbf395 | ||
|
|
6c177df67c | ||
|
|
38d34ca4da | ||
|
|
b51f045ee5 | ||
|
|
6c30a06aef | ||
|
|
f572cdf785 | ||
|
|
30307c4616 | ||
|
|
b956a323cd | ||
|
|
e93e61b4a6 | ||
|
|
95c371f1d3 | ||
|
|
11845453d7 | ||
|
|
025cf86441 | ||
|
|
2a2f7fe88c | ||
|
|
d427d0643b | ||
|
|
620bfde695 | ||
|
|
5ae8a54ed3 | ||
|
|
7e48d8b2a7 | ||
|
|
06d9529509 | ||
|
|
147f6d382c | ||
|
|
b8f9517cdd | ||
|
|
1e29997dcc | ||
|
|
ce481b3f60 | ||
|
|
17412c64d7 | ||
|
|
a4e01bad93 | ||
|
|
29e033f496 | ||
|
|
d3227c09f1 | ||
|
|
f814da2f4c | ||
|
|
cb615dcd83 | ||
|
|
c85385ca98 | ||
|
|
ecbaa44582 | ||
|
|
2eb3f211da | ||
|
|
f0b344ee9d | ||
|
|
66e88d30a8 | ||
|
|
c9a31767e0 | ||
|
|
2f32a1c8e0 | ||
|
|
537dd06e57 | ||
|
|
5e48f8445c | ||
|
|
2bbd3ac1fb | ||
|
|
9331613fc8 | ||
|
|
93855ed623 | ||
|
|
1a70a27d89 | ||
|
|
377f12696b | ||
|
|
99b7dd4512 | ||
|
|
f9c9f6453a | ||
|
|
a11a5f5af6 | ||
|
|
78e598e3a5 | ||
|
|
4c2c2c40fd | ||
|
|
bd735eba63 | ||
|
|
5832f71729 | ||
|
|
1c56b6049a | ||
|
|
265644072e | ||
|
|
76d3be1433 | ||
|
|
894acf7b8e | ||
|
|
77a932e321 | ||
|
|
5ea803494a | ||
|
|
c8d7141c79 | ||
|
|
d038f66b2a | ||
|
|
0717ce9d1d | ||
|
|
313be7c78d | ||
|
|
26a8e46527 | ||
|
|
e1b299df81 | ||
|
|
885f15a306 | ||
|
|
a7d6cb13ac | ||
|
|
c1a53669c8 | ||
|
|
c0e6ebd70b | ||
|
|
e288092848 | ||
|
|
150ccf1716 | ||
|
|
836178d426 | ||
|
|
5f697cb672 | ||
|
|
e8cddcf723 | ||
|
|
4db74e2a88 | ||
|
|
b229a50c77 | ||
|
|
b2cf930893 | ||
|
|
8138e70d63 | ||
|
|
8fac612ec0 | ||
|
|
a6094d6682 | ||
|
|
55f930ef3d | ||
|
|
b4a8c1fbcf | ||
|
|
6f270fb0e3 | ||
|
|
2db54ee92e | ||
|
|
f1706ae317 | ||
|
|
08994cb97c | ||
|
|
2a840c147e | ||
|
|
86f243a874 | ||
|
|
1e278de4cc | ||
|
|
1e1a38e780 | ||
|
|
404e69426b | ||
|
|
d229360a8d | ||
|
|
1eaf9dc777 | ||
|
|
c0f9708fde | ||
|
|
cfc49b4571 | ||
|
|
010dd34e7c | ||
|
|
16f08cbed5 | ||
|
|
847d135942 | ||
|
|
07cea66ccb | ||
|
|
ec5c9ebe6e | ||
|
|
eae62d0004 | ||
|
|
d27023a30d | ||
|
|
504432ed57 | ||
|
|
c495769751 | ||
|
|
1ae613f4e4 | ||
|
|
41f47fb72c | ||
|
|
0b0a4c8ba2 | ||
|
|
7f12f63c3a | ||
|
|
b5592de30e | ||
|
|
f834238d44 | ||
|
|
69273bef0a | ||
|
|
8722fb84a6 | ||
|
|
3b6ff1b9f9 | ||
|
|
b1e4b59781 | ||
|
|
99fc012d72 | ||
|
|
d4a130bb1b | ||
|
|
7206308e7f | ||
|
|
9e98a2c864 | ||
|
|
65ea042302 | ||
|
|
0d4c0c1a27 | ||
|
|
bfd3a685d6 | ||
|
|
d6f406e633 | ||
|
|
099f3fd812 | ||
|
|
5851bf1138 | ||
|
|
c89729cf67 | ||
|
|
09856b911b | ||
|
|
23224f6e99 | ||
|
|
e0200cf6f0 | ||
|
|
89f95e9bad | ||
|
|
656c5f3113 | ||
|
|
eacb31a89f | ||
|
|
87cdda0086 | ||
|
|
46f9c3c7d4 | ||
|
|
c8dea359db | ||
|
|
fb05e085fe | ||
|
|
7940e7dc9c | ||
|
|
f916fa3b31 | ||
|
|
39596f3398 | ||
|
|
6a8454ded3 | ||
|
|
3ff3975767 | ||
|
|
0a0b36686d | ||
|
|
576b33d46a | ||
|
|
6837e875a3 | ||
|
|
971f086785 | ||
|
|
835444be72 | ||
|
|
ce3cab93d5 | ||
|
|
50417cf758 | ||
|
|
6ec40eca1a | ||
|
|
b5cb68ac43 | ||
|
|
f39a6216ee | ||
|
|
19590812c0 | ||
|
|
b7fd3a3fc9 | ||
|
|
9addf77342 | ||
|
|
670ace18ae | ||
|
|
d1f187ecfd | ||
|
|
60a8648776 | ||
|
|
477a64e2b2 | ||
|
|
e0e6fe44e3 | ||
|
|
996727ed89 | ||
|
|
1f69e9b94c | ||
|
|
bfd6f76a7d | ||
|
|
7dcfd1e019 | ||
|
|
fdfd168060 | ||
|
|
0a07fd99db | ||
|
|
6629d9f892 | ||
|
|
fd8f0044fe | ||
|
|
5eafe15901 | ||
|
|
4ee5b2c4a9 | ||
|
|
616b226f74 | ||
|
|
40c1a46e99 | ||
|
|
a698bdbc57 | ||
|
|
8318a98a60 | ||
|
|
6b84db83e0 | ||
|
|
680835f815 | ||
|
|
d5c2db437e | ||
|
|
be70559584 | ||
|
|
ec88a22a94 | ||
|
|
056fb6d952 | ||
|
|
ab1e6fb08f | ||
|
|
af159c5695 | ||
|
|
07de512bf1 | ||
|
|
de804d7245 | ||
|
|
1f13c8c833 | ||
|
|
15ac07f7b6 | ||
|
|
b4e4325a7c | ||
|
|
4811e35fa3 | ||
|
|
664290ab54 | ||
|
|
88bfa1b89c | ||
|
|
9a29ae2267 | ||
|
|
bc04e63475 | ||
|
|
bc7c212370 | ||
|
|
2e2af8d918 | ||
|
|
e991684a39 | ||
|
|
7d372da738 | ||
|
|
c4d372d5b6 | ||
|
|
1c3b2d7186 | ||
|
|
abb12a9d81 | ||
|
|
4c487b9477 | ||
|
|
3ed79a5c18 | ||
|
|
38c81328e9 | ||
|
|
f041f1d198 | ||
|
|
83864ffe63 | ||
|
|
65af4fc74a | ||
|
|
64c3c81629 | ||
|
|
90574aabef | ||
|
|
580d114405 | ||
|
|
ac358a04a7 | ||
|
|
1963fdceae | ||
|
|
ead6fee1a7 | ||
|
|
3cd9c81c1c | ||
|
|
801b37bd2a | ||
|
|
9335c24d6c | ||
|
|
d080aae128 | ||
|
|
b4d42a84e2 | ||
|
|
c5e888a3dd | ||
|
|
a8781b51b4 | ||
|
|
7405392299 | ||
|
|
21fbb5e38f | ||
|
|
bb65193bff | ||
|
|
3081269e6f | ||
|
|
96bb76222e | ||
|
|
681bd7eb88 | ||
|
|
aa21284270 | ||
|
|
56fb68ca86 | ||
|
|
ffd27cef48 | ||
|
|
2b9ba4049e | ||
|
|
acebd2df11 | ||
|
|
76963dc49c | ||
|
|
d9c6bbbd94 | ||
|
|
cacc3c2057 | ||
|
|
11947c3f1f | ||
|
|
b171a2ed03 | ||
|
|
f1ca155cea | ||
|
|
313879d6ad | ||
|
|
29d54ab69b | ||
|
|
fc5dbc3016 | ||
|
|
4085b10ec2 | ||
|
|
888d122dcf | ||
|
|
d0c4873dc7 | ||
|
|
6446e0dfd3 | ||
|
|
2d2fa49130 | ||
|
|
5f2a934e3d | ||
|
|
fe8ddb71d9 | ||
|
|
d945ee87a1 | ||
|
|
f109e623f1 | ||
|
|
54768815c6 | ||
|
|
b7ba3f0d93 | ||
|
|
0737f45d4f | ||
|
|
a6419eeb3c | ||
|
|
fb991a4474 | ||
|
|
a4da6452c3 | ||
|
|
0e1ee3f5ce | ||
|
|
33fccc4861 | ||
|
|
f704f47a49 | ||
|
|
2280000005 | ||
|
|
8e3d7b026c | ||
|
|
f8631b98ee | ||
|
|
95094d3789 | ||
|
|
5981e43281 | ||
|
|
b64a3dd87a | ||
|
|
43f2c66ea7 | ||
|
|
505941259e | ||
|
|
67a2cd9229 | ||
|
|
c94d67892e | ||
|
|
5abaaaf7eb | ||
|
|
92bccc796b | ||
|
|
82006fcc93 | ||
|
|
35a458c782 | ||
|
|
71b01adc7b | ||
|
|
081d4275cf | ||
|
|
d8bb208a85 | ||
|
|
e6c2a65159 | ||
|
|
fe6d4a8eca | ||
|
|
cbd661e0cd | ||
|
|
b601051b21 | ||
|
|
90a772b193 | ||
|
|
d3dee71c24 | ||
|
|
ebd2c1323d | ||
|
|
b1aa737a05 | ||
|
|
c09b07fbb3 | ||
|
|
fb9f4c4d44 | ||
|
|
c6427fe140 | ||
|
|
626356842d | ||
|
|
1b5393db36 | ||
|
|
469931514a | ||
|
|
52a3f5b763 | ||
|
|
32ce703a98 | ||
|
|
aafc4cb2c9 | ||
|
|
8065c54fe9 | ||
|
|
3e2f61c439 | ||
|
|
c3869f2383 | ||
|
|
debc3b5bbb | ||
|
|
2759899646 | ||
|
|
4c931b2ec7 | ||
|
|
9a5be7bb92 | ||
|
|
462ccd9ff1 | ||
|
|
dfa47b454a | ||
|
|
c85378d984 | ||
|
|
82dfcf43de | ||
|
|
f03c791879 | ||
|
|
b17fa2513e | ||
|
|
abeea1d82d | ||
|
|
e9e869f4d5 | ||
|
|
887bd34b2f | ||
|
|
75d48e65ea | ||
|
|
19cd4d4bc0 | ||
|
|
0fc34a1139 | ||
|
|
85dd766853 | ||
|
|
a51b0528d3 | ||
|
|
1c32206120 | ||
|
|
65469442ad | ||
|
|
1370b308e2 | ||
|
|
09f21f1e21 | ||
|
|
8601e86f11 | ||
|
|
1ed3803654 | ||
|
|
893eac06e5 | ||
|
|
5469dd1b8f | ||
|
|
fb377229cd | ||
|
|
a5d4653b6e | ||
|
|
46c89fa3e9 | ||
|
|
2fdf260208 | ||
|
|
2c44fc22a7 | ||
|
|
16cca68de8 | ||
|
|
cfe0bfd911 | ||
|
|
3cad4e0371 | ||
|
|
9f09b6ef18 | ||
|
|
5e6cfc3062 | ||
|
|
aaa60cd17e | ||
|
|
5fedaa0eb8 | ||
|
|
532566ba1f | ||
|
|
62d59088df | ||
|
|
321265aa3b | ||
|
|
3cc832992d | ||
|
|
260c604942 | ||
|
|
19497a9bf2 | ||
|
|
f7076ecf36 | ||
|
|
9d74387072 | ||
|
|
f34f634824 | ||
|
|
bd3255760b | ||
|
|
941143858b | ||
|
|
ec8695bc13 | ||
|
|
9700eb126b | ||
|
|
aec57258b3 | ||
|
|
284009683d | ||
|
|
4f4d47fdf2 | ||
|
|
b6fb6f6b60 | ||
|
|
c7d364b385 | ||
|
|
3e37848f07 | ||
|
|
bc76a5d184 | ||
|
|
562dcfd295 | ||
|
|
18f1b32ecb | ||
|
|
ca94ea8ab5 | ||
|
|
b694a309e8 | ||
|
|
9d2dc7911b | ||
|
|
6ad882c861 | ||
|
|
536d5187a0 | ||
|
|
9809eed735 | ||
|
|
83750628d1 | ||
|
|
c270efdfb3 | ||
|
|
a0d1030096 | ||
|
|
f243c00dda | ||
|
|
1827af37cf | ||
|
|
d5ee9957f9 | ||
|
|
f683ddf16b | ||
|
|
441bf421cf | ||
|
|
6778187074 | ||
|
|
40a5d0a4b0 | ||
|
|
e2913f65c4 | ||
|
|
c99345ee99 | ||
|
|
6daffe5406 | ||
|
|
7d2a581a58 | ||
|
|
647382b08d | ||
|
|
c352257070 | ||
|
|
6bb50e1293 | ||
|
|
33f874d0cf | ||
|
|
ef78334c0f | ||
|
|
3619edcb8a | ||
|
|
e0dd82f267 | ||
|
|
cca5482221 | ||
|
|
8581059c3a | ||
|
|
8f7766cc61 | ||
|
|
58540ae93d | ||
|
|
b1fcd83797 | ||
|
|
da5323c2fa | ||
|
|
7ab8d60458 | ||
|
|
2e286dad30 | ||
|
|
006da86a39 | ||
|
|
0dd06d666f | ||
|
|
b5e0f01d74 | ||
|
|
5bdab5b0ee | ||
|
|
63307d201e | ||
|
|
a574b40929 | ||
|
|
5628da627c | ||
|
|
45b22c9c3f | ||
|
|
72e2062176 | ||
|
|
59ef300206 | ||
|
|
2ac7cad717 | ||
|
|
6c27bf5048 | ||
|
|
c7ae04d1c5 | ||
|
|
d2bacad469 | ||
|
|
5957c212a7 | ||
|
|
9f7814c8b8 | ||
|
|
2c7f2954f7 | ||
|
|
0b0b58c938 | ||
|
|
b9441c769b | ||
|
|
9ac5135a68 | ||
|
|
b9f428a589 | ||
|
|
3fa38a1a23 | ||
|
|
2e46f73f35 | ||
|
|
220e35674b | ||
|
|
dada909a10 | ||
|
|
432d24ab1a | ||
|
|
43d54f9ce7 | ||
|
|
29ce87273e | ||
|
|
bd1d6012dc | ||
|
|
513a6e5bce | ||
|
|
70f8f6a169 | ||
|
|
4b71933489 | ||
|
|
67fe179d1b | ||
|
|
453cdfd756 | ||
|
|
29c5f7a5d5 | ||
|
|
7541d9b258 | ||
|
|
30b02003a7 | ||
|
|
a81468c45f | ||
|
|
e5630e1c6a | ||
|
|
43f278356d | ||
|
|
65ba2606be | ||
|
|
c8bb359b74 | ||
|
|
e6e1c02c96 | ||
|
|
887636beb1 | ||
|
|
cfff4106f1 | ||
|
|
ae15530bfe | ||
|
|
4f2d0913fe | ||
|
|
546c67c49b | ||
|
|
6c2a1e1760 | ||
|
|
5d5b9fe63d | ||
|
|
a3473c08d3 | ||
|
|
2cbaebe6c5 | ||
|
|
9d5e117f6f | ||
|
|
6ca11d1b6a | ||
|
|
036cdbe7fb | ||
|
|
5abeee69e3 | ||
|
|
b4eb29253c | ||
|
|
e1ac5dc63c | ||
|
|
9f986ce10c | ||
|
|
55371f4cff | ||
|
|
54d530d448 | ||
|
|
544b9f3eed | ||
|
|
1e5cda65a1 | ||
|
|
85af25b7d1 | ||
|
|
0174d698a8 | ||
|
|
f55c4f6bd2 | ||
|
|
c543729671 | ||
|
|
f9c4b5ea7d | ||
|
|
dfb16b4493 | ||
|
|
37955a5299 | ||
|
|
5cc8d872b4 | ||
|
|
ef2859bbc8 | ||
|
|
0fd508ad32 | ||
|
|
f3e18baa00 | ||
|
|
ea20a11817 | ||
|
|
4982a250a9 | ||
|
|
c4fcf55652 | ||
|
|
beab362b2e | ||
|
|
8cc7e589d2 | ||
|
|
f7b55967ba | ||
|
|
e5f9de3aa7 | ||
|
|
433eff476a | ||
|
|
c5d79494d8 | ||
|
|
59149b5702 | ||
|
|
611f7f4e94 | ||
|
|
9a13f007e2 | ||
|
|
08a8e8cf3b | ||
|
|
0e14670605 | ||
|
|
9215c797bc | ||
|
|
7300469f71 | ||
|
|
243f980479 | ||
|
|
6ec0f97e37 | ||
|
|
15c458d349 | ||
|
|
ea36338b2e | ||
|
|
a833c9f701 | ||
|
|
e3323df4bd | ||
|
|
5f60dc649c | ||
|
|
39444fd45f | ||
|
|
4a31c30fa5 | ||
|
|
b055132b89 | ||
|
|
a10bc4fdaa | ||
|
|
41c6b54243 | ||
|
|
3859256312 | ||
|
|
d746ea9579 | ||
|
|
f7dcac6967 | ||
|
|
c18f81a67f | ||
|
|
680ffffe9c | ||
|
|
d5745e3595 | ||
|
|
b6e4a16809 | ||
|
|
5614bffb25 | ||
|
|
8ab7c96398 | ||
|
|
14eae5108d | ||
|
|
66a246bd31 | ||
|
|
191dd0055c | ||
|
|
5cb5b8b5f7 | ||
|
|
1393eac44c | ||
|
|
20aee85b44 | ||
|
|
0b11ce6656 | ||
|
|
c94e4d888a | ||
|
|
0cdd822207 | ||
|
|
8c8ec85aa4 | ||
|
|
3fa86f6f68 | ||
|
|
b0d37c8861 | ||
|
|
4bd1cf888c | ||
|
|
283a969d68 | ||
|
|
2f03ec08b5 | ||
|
|
6c6a7720f2 | ||
|
|
31d28179c2 | ||
|
|
15ea759813 | ||
|
|
030915208b | ||
|
|
8607ae51fc | ||
|
|
650b9eddae | ||
|
|
9ef891e82c | ||
|
|
c3ec789ecd | ||
|
|
1e6b9b04de | ||
|
|
cf64e2574c | ||
|
|
ea3fd42495 | ||
|
|
a54b3bb0a8 | ||
|
|
ba957f84d3 | ||
|
|
4065352c7e | ||
|
|
9f657fee5b | ||
|
|
2bc7dfebe6 | ||
|
|
b566fa8770 | ||
|
|
9acd76b571 | ||
|
|
d53533fbd1 | ||
|
|
2826484206 | ||
|
|
00570a6ac9 | ||
|
|
56ff3c5270 | ||
|
|
a721e7083f | ||
|
|
399988aaed | ||
|
|
0fa789c1f9 | ||
|
|
3d60b4158e | ||
|
|
606eefa5c6 | ||
|
|
5fac520b2a | ||
|
|
1d435b9f49 | ||
|
|
bc9cdd5de0 | ||
|
|
9b08318077 | ||
|
|
0db496e2b8 | ||
|
|
4e2d825c63 | ||
|
|
d41e73c79c | ||
|
|
907c3dc195 | ||
|
|
8250a4248f | ||
|
|
6ddabc0f0f | ||
|
|
e46883e27e | ||
|
|
a05a6d06fa | ||
|
|
afb121b0af | ||
|
|
e30d7e7f6c | ||
|
|
ff4898fd42 | ||
|
|
9feb900f3e | ||
|
|
42cf8ea91d | ||
|
|
92cabe2d88 | ||
|
|
f9fbace89d | ||
|
|
c3fe4b585b | ||
|
|
e72cf013cd | ||
|
|
699272e4dc | ||
|
|
f0b98d4fe4 | ||
|
|
1c8101b707 | ||
|
|
d5641efa10 | ||
|
|
7402987fd2 | ||
|
|
0d1276157f | ||
|
|
a216625bd0 | ||
|
|
4aaac3a91c | ||
|
|
ab2165e6d6 | ||
|
|
fa2f0c93e6 | ||
|
|
4332b970c9 | ||
|
|
cdd090b11e | ||
|
|
80a2241ec0 | ||
|
|
3316890ffa | ||
|
|
127ead7452 | ||
|
|
350671ff86 | ||
|
|
5a6885bac8 | ||
|
|
2c713b5817 | ||
|
|
5811276bb7 | ||
|
|
43c7c4f347 | ||
|
|
1071c3040c | ||
|
|
1ac897bc5e | ||
|
|
dcf66590d2 | ||
|
|
1bfe2230e4 | ||
|
|
435aaff20e | ||
|
|
51f404b448 | ||
|
|
fdece0a0cc | ||
|
|
8759e7d4d6 | ||
|
|
064f82986c | ||
|
|
6498e7a8fd | ||
|
|
17e6921016 | ||
|
|
a88902ed7e | ||
|
|
fb964539b8 | ||
|
|
c7f698e967 | ||
|
|
1abc8e5500 | ||
|
|
50d9f1687a | ||
|
|
b60461fb95 | ||
|
|
756d578287 | ||
|
|
a5d027ab66 | ||
|
|
19e13cf3d2 | ||
|
|
f1aab6402f | ||
|
|
31dd4824d3 | ||
|
|
04937652f4 | ||
|
|
a51943ad52 | ||
|
|
1cbaff643f | ||
|
|
5e8396a60e | ||
|
|
29c0250d49 | ||
|
|
d32a9d7ec3 | ||
|
|
d12b37f90e | ||
|
|
76b5981b41 | ||
|
|
fb62b64201 | ||
|
|
8ab652c6cb | ||
|
|
36d0a27770 | ||
|
|
e6438cf8c3 | ||
|
|
e447582b85 | ||
|
|
5da41e46d3 | ||
|
|
e80a5adfd4 | ||
|
|
bb21dea84c | ||
|
|
436beea3a9 | ||
|
|
d507ea00a9 | ||
|
|
da8ff6a7d8 | ||
|
|
bcbff960a1 | ||
|
|
096bace0da | ||
|
|
63ea6ef4fb | ||
|
|
4f054550b7 | ||
|
|
3937fc7dfc | ||
|
|
6448903b52 | ||
|
|
e6b290df27 | ||
|
|
3c75a46be4 | ||
|
|
ca7d3b5a5b | ||
|
|
4959f5da49 | ||
|
|
75bdcd096f | ||
|
|
152522b3f2 | ||
|
|
5d1a718214 | ||
|
|
5acc9b149a | ||
|
|
8965f30215 | ||
|
|
fd4289c582 | ||
|
|
f7b957b589 | ||
|
|
bda06f76c0 | ||
|
|
139f31dc17 | ||
|
|
8d318dee6c | ||
|
|
cd3db26cc9 | ||
|
|
654ca5463d | ||
|
|
f34b180ca9 | ||
|
|
73f2527486 | ||
|
|
9e5395c3da | ||
|
|
0236ab5694 | ||
|
|
9018be2dfd | ||
|
|
2f46856f95 | ||
|
|
521951b55d | ||
|
|
da4b0a41e1 | ||
|
|
7482ba0b3c | ||
|
|
1c025e9795 | ||
|
|
9a3b86908a | ||
|
|
860640fb8d | ||
|
|
41cfe44b5e | ||
|
|
16c237d3d1 | ||
|
|
975081a3a8 | ||
|
|
57f7788ec2 | ||
|
|
f14a58dea4 | ||
|
|
55b511c396 | ||
|
|
62b3e73b25 | ||
|
|
1210f49bb5 | ||
|
|
1de1623590 | ||
|
|
b343dc5611 | ||
|
|
1fbed902ed | ||
|
|
9cf6ac32d6 | ||
|
|
2942ecb230 | ||
|
|
c63658973c | ||
|
|
9ffee8c94a | ||
|
|
3306d4d34d | ||
|
|
4fbeec9d61 | ||
|
|
2b2cdee799 | ||
|
|
1230016bf0 | ||
|
|
4bb8397ae3 | ||
|
|
1281e6e6c4 | ||
|
|
2c28079188 | ||
|
|
fadebedff0 | ||
|
|
e86045694a | ||
|
|
8ba8dd23b7 | ||
|
|
f846a789b7 | ||
|
|
b07f883979 | ||
|
|
67ee56be69 | ||
|
|
6ff05dae07 | ||
|
|
29b752f8b2 | ||
|
|
68b52c48b7 | ||
|
|
21ff71b0eb | ||
|
|
21bf37f6e4 | ||
|
|
4a2760ffd2 | ||
|
|
1ec7ba52e1 | ||
|
|
e1a923dc5a | ||
|
|
6a38697261 | ||
|
|
0d2d7e3a30 | ||
|
|
944c662d8a | ||
|
|
5b75a623ef | ||
|
|
e111852270 | ||
|
|
3d50251e0a | ||
|
|
5aa892995a | ||
|
|
6652f72352 | ||
|
|
dc4d1ee7bd | ||
|
|
5abb036e9b | ||
|
|
ac1c19dee7 | ||
|
|
21af7fc4aa | ||
|
|
04bbad660b | ||
|
|
ec1700ba29 | ||
|
|
8e002c87b3 | ||
|
|
1b0b35f254 | ||
|
|
35a1f5481a | ||
|
|
f67b65eea8 | ||
|
|
8e219c5661 | ||
|
|
08430e689f | ||
|
|
aed2324b4d | ||
|
|
339416b821 | ||
|
|
d8cddf61f9 | ||
|
|
d0c46d9ae5 | ||
|
|
509d19e6fd | ||
|
|
01ed5c4009 | ||
|
|
7051653610 | ||
|
|
31f80b9eae | ||
|
|
4c97ea116c | ||
|
|
db170dd452 | ||
|
|
ca2c42df6b | ||
|
|
e83024d3fa | ||
|
|
70be7312f1 | ||
|
|
5ae984b946 | ||
|
|
2e137b3954 | ||
|
|
8a85729dc1 | ||
|
|
47d4d87637 | ||
|
|
2020486546 | ||
|
|
e76c012ec7 | ||
|
|
eabdbd1d3c | ||
|
|
abf1296ed4 | ||
|
|
1e21f9c4f8 | ||
|
|
af8a815348 | ||
|
|
130f31ca79 | ||
|
|
37c5ed2ed9 | ||
|
|
919b8bc4ac | ||
|
|
65680b2343 | ||
|
|
56845d8cc2 | ||
|
|
3feea4503f | ||
|
|
2efd89d029 | ||
|
|
de73c6d1cd | ||
|
|
c4d6596ba3 | ||
|
|
b9b1e374bf | ||
|
|
d0470e296e | ||
|
|
888f112b78 | ||
|
|
22396493b2 | ||
|
|
28e6c79cf3 | ||
|
|
51c2432918 | ||
|
|
3e855cd277 | ||
|
|
43447c4254 | ||
|
|
812c08efb4 | ||
|
|
56950a78db | ||
|
|
ec4f567f31 | ||
|
|
4f34234492 | ||
|
|
fd6a711f54 | ||
|
|
2392ae1900 | ||
|
|
f87069a3b0 | ||
|
|
4baa9041cc | ||
|
|
3a5bbe4cbe | ||
|
|
887fb3ebaa | ||
|
|
e33cff44b5 | ||
|
|
827b495b8b | ||
|
|
3f9df2b86b | ||
|
|
d8a80a35a0 | ||
|
|
2db5256143 | ||
|
|
8b53548b9e | ||
|
|
41549de960 | ||
|
|
4c30681839 | ||
|
|
df01130bb1 | ||
|
|
e0ddf30bf6 | ||
|
|
d4f8b12442 | ||
|
|
fe5eede555 | ||
|
|
f3f6116c57 | ||
|
|
1d82b4057a | ||
|
|
ddefe6cf8c | ||
|
|
a61ff195b5 | ||
|
|
a2beb234e8 | ||
|
|
97e455f21b | ||
|
|
63d47c051d | ||
|
|
64032a35ae | ||
|
|
cc741e1ac7 | ||
|
|
0030966200 | ||
|
|
ed197d4c30 | ||
|
|
a0b5840320 | ||
|
|
0628499690 | ||
|
|
ecdd922d96 | ||
|
|
9e6393c6b1 | ||
|
|
31491a6acc | ||
|
|
03255a5a0f | ||
|
|
04e4b63c20 | ||
|
|
d173662fe0 | ||
|
|
58fb83c45b | ||
|
|
eb8db2303b | ||
|
|
2c594da214 | ||
|
|
bb9d511e52 | ||
|
|
1a990ee332 | ||
|
|
e331da58a6 | ||
|
|
f1fd7f1e01 | ||
|
|
3568e508d0 | ||
|
|
eaceeae0f7 | ||
|
|
c86b95038d | ||
|
|
03560c4b83 | ||
|
|
725298ea4b | ||
|
|
0a23654649 | ||
|
|
68879d50fa | ||
|
|
4b4f8fbf25 | ||
|
|
7765724d51 | ||
|
|
de1f8f8345 | ||
|
|
54cdda032e | ||
|
|
4e8b155c74 | ||
|
|
e6432d78b2 | ||
|
|
a1160414b8 | ||
|
|
ace88cdd2c | ||
|
|
7997d7fdc3 | ||
|
|
2ae2c25c5d | ||
|
|
5467089770 | ||
|
|
32c4c8ace4 | ||
|
|
2b5a48232f | ||
|
|
295f5e5dee | ||
|
|
81f34b2f33 | ||
|
|
fea7c7e48f | ||
|
|
5a628cf7d9 | ||
|
|
7d4005156b | ||
|
|
3d8049e32d | ||
|
|
8d4a4049f4 | ||
|
|
c9b37f9689 | ||
|
|
39c72682b8 | ||
|
|
91e3c36e45 | ||
|
|
7628ff39dc | ||
|
|
3d41ea09a8 | ||
|
|
32f67637cd | ||
|
|
2eeea03973 | ||
|
|
3cb29af876 | ||
|
|
43f41fbfaa | ||
|
|
c6b4675982 | ||
|
|
e6555083d4 | ||
|
|
2456662e5e | ||
|
|
e478a8c00d | ||
|
|
14253e7ff4 | ||
|
|
a66979fe1e | ||
|
|
e900aa97e2 | ||
|
|
79285a0f46 | ||
|
|
35ab498a87 | ||
|
|
faa6609dac | ||
|
|
b7a51f3a9c | ||
|
|
5c30910759 | ||
|
|
7d3da6f850 | ||
|
|
1db3029abc | ||
|
|
563180f7d4 | ||
|
|
33d083c034 | ||
|
|
9ac0f8119e | ||
|
|
fae82dda00 | ||
|
|
e04594339c | ||
|
|
1776597131 | ||
|
|
9f1a375f10 | ||
|
|
bff001187f | ||
|
|
83c1e03c5c | ||
|
|
735fcd5e77 | ||
|
|
139cbe4f72 | ||
|
|
6d8d89042b | ||
|
|
5650a0c306 | ||
|
|
a991eedcf5 | ||
|
|
3a314fcea8 | ||
|
|
64b0760faa | ||
|
|
7af05fcc93 | ||
|
|
9541e30e86 | ||
|
|
770e1e399c | ||
|
|
740f6b0d5a | ||
|
|
27a0bdcae0 | ||
|
|
ec422fb70e | ||
|
|
b6d3f60791 | ||
|
|
acf64c4178 | ||
|
|
f1faec8829 | ||
|
|
4e1f5377d1 | ||
|
|
6b68a70b5f | ||
|
|
a2099ed44f | ||
|
|
9dee44ae2f | ||
|
|
e8ad398862 | ||
|
|
bb6a1f690d | ||
|
|
6bb97495ba | ||
|
|
4779ddd865 | ||
|
|
f8b4f7289e | ||
|
|
8b82369347 | ||
|
|
b1369b4721 | ||
|
|
915012950c | ||
|
|
f8a3f14e4f | ||
|
|
a78718b934 | ||
|
|
de11c5217b | ||
|
|
9a37503bbe | ||
|
|
fd7239af69 | ||
|
|
1b98ce355a | ||
|
|
f46551de45 | ||
|
|
a987942761 | ||
|
|
1d0067a873 | ||
|
|
7fc7492d86 | ||
|
|
1c692f019b | ||
|
|
eed7888f85 | ||
|
|
024e8b107e | ||
|
|
42b6ef8ccd | ||
|
|
990d4c799f | ||
|
|
92f789eba4 | ||
|
|
9f0fb6c601 | ||
|
|
0a67c13052 | ||
|
|
da1bc9878b | ||
|
|
1a08c41048 | ||
|
|
2574ca4b21 | ||
|
|
ccbd68bb3c | ||
|
|
de42925264 | ||
|
|
4d4ea792e7 | ||
|
|
912fb6c2d5 | ||
|
|
4c6917e1d6 | ||
|
|
2869b86ea4 | ||
|
|
75c8b88cdd | ||
|
|
6079158b21 | ||
|
|
7aa50b9b19 | ||
|
|
5329fc481e | ||
|
|
b569733478 | ||
|
|
94a089bc2b | ||
|
|
0f8721fa52 | ||
|
|
4352e220ac | ||
|
|
159f595117 | ||
|
|
6194483b73 | ||
|
|
7455e7eba9 | ||
|
|
c4f28097aa | ||
|
|
3e3554d37c | ||
|
|
1ed19fc623 | ||
|
|
13c2a8a510 | ||
|
|
735fbfdf49 | ||
|
|
22570c3181 | ||
|
|
a2e7b4c5fa | ||
|
|
735c0f8414 | ||
|
|
271a098b64 | ||
|
|
3d19fb6d53 | ||
|
|
3380390b7a | ||
|
|
654514c5b2 | ||
|
|
8f830d78ba | ||
|
|
339e2c13b0 | ||
|
|
8e17496421 | ||
|
|
6224df56a6 | ||
|
|
69adef7ed5 | ||
|
|
36275b0c2d | ||
|
|
cedb11925f | ||
|
|
433d2ee9f1 | ||
|
|
1b63306a97 | ||
|
|
63ff014070 | ||
|
|
19d2424e05 | ||
|
|
029d0f7538 | ||
|
|
6560bf82f3 | ||
|
|
f36837398c | ||
|
|
e53009e253 | ||
|
|
920f77e3c1 | ||
|
|
ae3ffcf4ea | ||
|
|
c2834f9298 | ||
|
|
212132958f | ||
|
|
868fa20bc9 | ||
|
|
b7644319e8 | ||
|
|
c0b85ad6ad | ||
|
|
e3b4042c9c | ||
|
|
755da17974 | ||
|
|
bfaef1eaf5 | ||
|
|
b1f8d46fca | ||
|
|
cef4e5ff38 | ||
|
|
1b463058e3 | ||
|
|
5b81dbcfa3 | ||
|
|
86c43d2e0f | ||
|
|
7d9f241d63 | ||
|
|
90c72c31a5 | ||
|
|
93b11905e5 | ||
|
|
764126039c | ||
|
|
b39b6023c5 | ||
|
|
06a90199c5 | ||
|
|
86ef507cc7 | ||
|
|
1e7b730ce8 | ||
|
|
87b1404eda | ||
|
|
9f82afea25 | ||
|
|
0a44f97cb8 | ||
|
|
b4686a0f78 | ||
|
|
e28c3c7ec0 | ||
|
|
4a4b17e0d3 | ||
|
|
6524838950 | ||
|
|
d13734add3 | ||
|
|
9609f5ffb5 | ||
|
|
d2c733742f | ||
|
|
6dfc5b36b8 | ||
|
|
7bb4923391 | ||
|
|
6d7d48af0d | ||
|
|
b32a0fd286 | ||
|
|
1daacdb408 | ||
|
|
07b63894cb | ||
|
|
4eb4010c1a | ||
|
|
74f6c21747 | ||
|
|
a4c17c1397 | ||
|
|
a86764d99b | ||
|
|
6220e09f61 | ||
|
|
cabd14fa15 | ||
|
|
f3c368357c | ||
|
|
a4cdd0bc00 | ||
|
|
6eae79ac55 | ||
|
|
ecf85cb083 | ||
|
|
c0a224aba3 | ||
|
|
f214f4d4f4 | ||
|
|
0883d8213b | ||
|
|
1fcbc17b7d | ||
|
|
28edc2604a | ||
|
|
711d29f8e4 | ||
|
|
caeb274e28 | ||
|
|
f881dae817 | ||
|
|
5df05d1670 | ||
|
|
9e06ab17b9 | ||
|
|
a40467152c | ||
|
|
8dad0f93e8 | ||
|
|
8f7cf2990f | ||
|
|
d96fc5d02a | ||
|
|
fadb8d61ba | ||
|
|
9974e9a46b | ||
|
|
63a7b2d2d9 | ||
|
|
2bfe19152d | ||
|
|
b5b6e95748 | ||
|
|
7b056709c0 | ||
|
|
3771af0af4 | ||
|
|
b6a6ffa4c0 | ||
|
|
0a35ccc6bd | ||
|
|
18b2dea9a4 | ||
|
|
b705e19082 | ||
|
|
f3b6f4f8da | ||
|
|
86cf3eb71c | ||
|
|
4ece86eb41 | ||
|
|
596e322543 | ||
|
|
2895c57b29 | ||
|
|
7b07ea67dc | ||
|
|
6b0e12fd6f | ||
|
|
4a886e519f | ||
|
|
0612829fb0 | ||
|
|
fb33f9c54b | ||
|
|
1da9d37521 | ||
|
|
e82df50d98 | ||
|
|
75ceae6ea6 | ||
|
|
c04870ba7b | ||
|
|
9e62715973 | ||
|
|
74bec18c2a | ||
|
|
b54cefc379 | ||
|
|
f4c4f784cd | ||
|
|
3a6b75870b | ||
|
|
66e483ebdc | ||
|
|
b4e880534e | ||
|
|
ff2090336f | ||
|
|
d8080933f5 | ||
|
|
b2820e190f | ||
|
|
fe1cabb88a | ||
|
|
4c5cfa8bc6 | ||
|
|
42bb865689 | ||
|
|
1a7e8d77ba | ||
|
|
3b6004e6ab | ||
|
|
f107dd78ec | ||
|
|
4e54f9fc07 | ||
|
|
02ae6ab3fd | ||
|
|
aa3b59af54 | ||
|
|
540bcff90d | ||
|
|
000e960306 | ||
|
|
7db699163b | ||
|
|
772374735d | ||
|
|
d71f4b4718 | ||
|
|
8342ca6c69 | ||
|
|
388d8db68d | ||
|
|
6b27d78030 | ||
|
|
9a5943bf76 | ||
|
|
5ef2fde8fb | ||
|
|
ecfda6512c | ||
|
|
f411cac350 | ||
|
|
1c578a710f | ||
|
|
f55d466cad | ||
|
|
5c26cfcb47 | ||
|
|
3bd845f3ff | ||
|
|
3757c0cdfb | ||
|
|
a24801ae8d | ||
|
|
0d91796bb3 | ||
|
|
6e83259e7f | ||
|
|
0cc5561c93 | ||
|
|
8795472c87 | ||
|
|
81518ae2e2 | ||
|
|
42027de3fc | ||
|
|
4ae02f46e9 | ||
|
|
17b85b3445 | ||
|
|
6078165993 | ||
|
|
18d0509c75 | ||
|
|
92385b6e1c | ||
|
|
2f86267f07 | ||
|
|
a75524561c | ||
|
|
f2028dc5af | ||
|
|
984235a12d | ||
|
|
f624a3ae8b | ||
|
|
dc66790e84 | ||
|
|
3a6c55fb51 | ||
|
|
f7c8b08bd2 | ||
|
|
5c2ef5b542 | ||
|
|
a0de2bfa10 | ||
|
|
99d65925e6 | ||
|
|
bd6ba3ac82 | ||
|
|
1f407c2a47 | ||
|
|
00b24eb0f4 | ||
|
|
46828cc157 | ||
|
|
751887ad6e | ||
|
|
d8198c2d87 | ||
|
|
bccc1419a6 | ||
|
|
2e610cf155 | ||
|
|
3aefc6e8a4 | ||
|
|
67a0fd1fb7 | ||
|
|
710ce4aaf9 | ||
|
|
ff2b4adfd7 | ||
|
|
9ef1913ed6 | ||
|
|
2c13aa097b | ||
|
|
afd78a37da | ||
|
|
fa6dd376bb | ||
|
|
0460bc79d9 | ||
|
|
073506bc55 | ||
|
|
c703b9ce89 | ||
|
|
e251f64d68 | ||
|
|
4fec72f178 | ||
|
|
e6eefc0c5e | ||
|
|
bc4a96836d | ||
|
|
51a72503b0 | ||
|
|
6b489db899 | ||
|
|
2b4d028a69 | ||
|
|
64e72b58fd | ||
|
|
cd95d4a5b9 | ||
|
|
a030bc9f17 | ||
|
|
f0e9469939 | ||
|
|
04d799863f | ||
|
|
7083168295 | ||
|
|
8f191ec3b8 | ||
|
|
f472405e59 | ||
|
|
d5bb919aa6 | ||
|
|
afb3a52833 | ||
|
|
c19ebfc3dc | ||
|
|
910347aef2 | ||
|
|
675f021368 | ||
|
|
3c0fc9b95f | ||
|
|
a1de76c42f | ||
|
|
55ad10370f | ||
|
|
868e98bf40 | ||
|
|
df9b6492e5 | ||
|
|
7de0d17853 | ||
|
|
68d3018cee | ||
|
|
772042ea85 | ||
|
|
ce17fd4bf3 | ||
|
|
2669488d85 | ||
|
|
30abab5572 | ||
|
|
5def69c0cd | ||
|
|
3e063525f3 | ||
|
|
88ca587eae | ||
|
|
dd93c6a116 | ||
|
|
5fba7db9be | ||
|
|
91e7d46fe1 | ||
|
|
f2eb4aac95 | ||
|
|
0342981212 | ||
|
|
c9d8a67b52 | ||
|
|
e81660d5c0 | ||
|
|
33e277e856 | ||
|
|
d1e31ab158 | ||
|
|
ea934b9539 | ||
|
|
6a688b7364 | ||
|
|
b141f9f3c8 | ||
|
|
942c2429c0 | ||
|
|
c4a8afa4c6 | ||
|
|
d0d4e391c5 | ||
|
|
dd4e09d387 | ||
|
|
60b68ff4ee | ||
|
|
2af8c15597 | ||
|
|
3f1fe4e33c | ||
|
|
e56a9d85ac | ||
|
|
9974ab67f5 | ||
|
|
1f32d014da | ||
|
|
232eec47d1 | ||
|
|
78f2864b90 | ||
|
|
39d5a97266 | ||
|
|
c97b1b8228 | ||
|
|
30bd28fca2 | ||
|
|
39ac195109 | ||
|
|
76ec285ba4 | ||
|
|
2ee5d42e24 | ||
|
|
480b4e467c | ||
|
|
7d8a6b2614 | ||
|
|
f9432a0287 | ||
|
|
f917b353e8 | ||
|
|
8ef4f6a538 | ||
|
|
c02675b407 | ||
|
|
ae7d2837b3 | ||
|
|
4684cfb508 | ||
|
|
d18221c542 | ||
|
|
665b92d83f | ||
|
|
055b207a9f | ||
|
|
6b7b77896d | ||
|
|
4b94ee113b | ||
|
|
b9d0e2d5c5 | ||
|
|
e5a063a87c | ||
|
|
8c2c464cb8 | ||
|
|
e47063bfe0 | ||
|
|
80861dffa9 | ||
|
|
8a13957db7 | ||
|
|
ae9300cac0 | ||
|
|
b1fe748fea | ||
|
|
56e199416f | ||
|
|
fe92820347 | ||
|
|
71030d67bd | ||
|
|
df4639ab71 | ||
|
|
09b685b24b | ||
|
|
20384e8945 | ||
|
|
e5a5a72e17 | ||
|
|
aadbb5a1d1 | ||
|
|
ab8944b1bf | ||
|
|
95d4cd3042 | ||
|
|
c3abfe5064 | ||
|
|
cbe99b0667 | ||
|
|
562e37ee7e | ||
|
|
f0ea9e37f9 | ||
|
|
728ce8cc48 | ||
|
|
333414fe94 | ||
|
|
9bfd028938 | ||
|
|
dce3206223 | ||
|
|
079df65dc0 | ||
|
|
800a18aff2 | ||
|
|
f09056323e | ||
|
|
e9b2625753 | ||
|
|
0cc8267286 | ||
|
|
7827dfb672 | ||
|
|
97b2940936 | ||
|
|
930b07c3af | ||
|
|
11d24b6614 | ||
|
|
319c49e64a | ||
|
|
0c90cac2c3 | ||
|
|
e95aa257aa | ||
|
|
5af3c90336 | ||
|
|
b9a7a74d5e | ||
|
|
dea7c2bd8e | ||
|
|
f8ecdf47f0 | ||
|
|
e49292894a | ||
|
|
2c4119d1eb | ||
|
|
dc7aef1d70 | ||
|
|
8c3b9d6083 | ||
|
|
7ea5461151 | ||
|
|
881369b949 | ||
|
|
01a0a2d542 | ||
|
|
65d8deac95 | ||
|
|
25804aeae2 | ||
|
|
6e1f34ed62 | ||
|
|
c3d582d87b | ||
|
|
6deb514992 | ||
|
|
2cd53196ea | ||
|
|
1e4f69d561 | ||
|
|
ce62fa2eed | ||
|
|
ce577d4844 | ||
|
|
9a6947427a | ||
|
|
f6022839c2 | ||
|
|
16dcc8bec1 | ||
|
|
c7b9c84312 | ||
|
|
53c3119ebb | ||
|
|
7c59d681a0 | ||
|
|
56a005241c | ||
|
|
94fe6fe05d | ||
|
|
2b0fa0f8a1 | ||
|
|
b42bcb2573 | ||
|
|
117997cd5b | ||
|
|
f10eba00ea | ||
|
|
5145f671a4 | ||
|
|
5b86ae5e8a | ||
|
|
9f41f64cd2 | ||
|
|
323e6e7f9f | ||
|
|
94a95b3e8f | ||
|
|
14154b2910 | ||
|
|
b07eb3cb45 | ||
|
|
bec5d6991e | ||
|
|
c3ad6da0c4 | ||
|
|
09cf037652 | ||
|
|
096a74d7c5 | ||
|
|
fd164a6c84 | ||
|
|
87d5982e58 | ||
|
|
f2fa9d000b | ||
|
|
af6f4ab938 | ||
|
|
ce1492ef3a | ||
|
|
2dfa954e1f | ||
|
|
a95c58df3b | ||
|
|
1269b08b1b | ||
|
|
cda9defe58 | ||
|
|
99248e843d | ||
|
|
6327c59d4f | ||
|
|
e467e899e1 | ||
|
|
5df226c2ab | ||
|
|
fb647e5219 | ||
|
|
05f28ba2fb | ||
|
|
9130e5923e | ||
|
|
64424b870b | ||
|
|
6f9e8f482c | ||
|
|
0d92f79fd8 | ||
|
|
360b4e0565 | ||
|
|
4aad91f687 | ||
|
|
924a47fc4f | ||
|
|
2c8643b0e9 | ||
|
|
96c4208bf8 | ||
|
|
98c66d19a0 | ||
|
|
ab244748d6 | ||
|
|
02190234a2 | ||
|
|
8952a30f0a | ||
|
|
ee5e815e2c | ||
|
|
888f296540 | ||
|
|
889c011a0f | ||
|
|
d80b709ea0 | ||
|
|
e486ef666f | ||
|
|
bfa57063d4 | ||
|
|
6dd795bda0 | ||
|
|
2045689ff2 | ||
|
|
b5bf863217 | ||
|
|
21349b23dc | ||
|
|
6b6bdb3542 | ||
|
|
b33caa6418 | ||
|
|
9f98070a58 | ||
|
|
3e654204fd | ||
|
|
f2ee514c75 | ||
|
|
5a2d2f47d6 | ||
|
|
7c8c124dbe | ||
|
|
428dfeee48 | ||
|
|
f5ec60c881 | ||
|
|
ae13473895 | ||
|
|
ae7ef6f610 | ||
|
|
9ec1312bd5 | ||
|
|
26c72fcd4e | ||
|
|
5c60aaefd3 | ||
|
|
0e4469150a | ||
|
|
f8781840af | ||
|
|
07e5b7cf54 | ||
|
|
fcfff77128 | ||
|
|
acd8b1c107 | ||
|
|
7c74d702a9 | ||
|
|
bf03d4332a | ||
|
|
91a1022227 | ||
|
|
4e811fd72e | ||
|
|
13f9578082 | ||
|
|
fe6b549184 | ||
|
|
d59cf4eb3f | ||
|
|
ec36df00af | ||
|
|
21f47e6f7a | ||
|
|
d8da8e4e7d | ||
|
|
42078107f1 | ||
|
|
d7b8b475f8 | ||
|
|
e5bdf96bc0 | ||
|
|
345cc1e304 | ||
|
|
5c80400ec7 | ||
|
|
ecca1f814e | ||
|
|
20f2f5b169 | ||
|
|
51e4512abd | ||
|
|
0620a76b58 | ||
|
|
cfb59ecc9b | ||
|
|
4e9ab7a72f | ||
|
|
f38f890849 | ||
|
|
7189d0bc82 | ||
|
|
31a0da32a8 | ||
|
|
24d29a63b6 | ||
|
|
c99fc44e17 | ||
|
|
65b3f4aaa0 | ||
|
|
3ebd1b30eb | ||
|
|
d34063aa32 | ||
|
|
824c8664ed | ||
|
|
a90b0101aa | ||
|
|
6bc0da30b0 | ||
|
|
528509e1bc | ||
|
|
2860ae6c49 | ||
|
|
bc4c6c44af | ||
|
|
3351f5f93c | ||
|
|
ec2004d8c2 | ||
|
|
a5f92314ed | ||
|
|
9393317aff | ||
|
|
991346d5bb | ||
|
|
6f71cb7c4e | ||
|
|
061bae6e04 | ||
|
|
daf209bd6b | ||
|
|
a6817579ce | ||
|
|
40f9bcf111 | ||
|
|
74ca7f627e | ||
|
|
0e88bcc30e | ||
|
|
59d90c95a1 | ||
|
|
ad09d28e80 | ||
|
|
e8f97c9e35 | ||
|
|
eb28ebb0f8 | ||
|
|
dc9e35f08d | ||
|
|
e28b448137 | ||
|
|
cafebe1604 | ||
|
|
31699bd186 | ||
|
|
afb466fb8b | ||
|
|
7a4aa46ae4 | ||
|
|
ef0da7eb66 | ||
|
|
a8e7bb8782 | ||
|
|
3f55039e7f | ||
|
|
513a045395 | ||
|
|
4856493efc | ||
|
|
c1896741d4 | ||
|
|
4cec791774 | ||
|
|
c124fa36d5 | ||
|
|
fb45433f15 | ||
|
|
d3cf79bf87 | ||
|
|
88cd6e4706 | ||
|
|
a51ab91662 | ||
|
|
1873d8107a | ||
|
|
9611ba3a9d | ||
|
|
ff71283e53 | ||
|
|
8ecad78ba3 | ||
|
|
9e75d3ed8f | ||
|
|
fb289799f4 | ||
|
|
1d81219aec | ||
|
|
2774113dab | ||
|
|
7f08d8c93a | ||
|
|
0604116814 | ||
|
|
743e9d4589 | ||
|
|
ba3d4aa5ba | ||
|
|
9bdd6f2b1f | ||
|
|
61f9e37612 | ||
|
|
7a1e2dd92f | ||
|
|
f1920d2713 | ||
|
|
cba9513bc9 | ||
|
|
6c47f66011 | ||
|
|
d2656136ab | ||
|
|
792083d23b | ||
|
|
c31833e997 | ||
|
|
e6251c3e40 | ||
|
|
1322edc7b1 | ||
|
|
9a3c9ba7be | ||
|
|
9e77f40a31 | ||
|
|
f3bc60bdd8 | ||
|
|
8aa7369125 | ||
|
|
84ba09a7d7 | ||
|
|
ffb6fbf825 | ||
|
|
1f3e5d9826 | ||
|
|
8ab08cf805 | ||
|
|
23825a2591 | ||
|
|
81bd994c0a | ||
|
|
56dafa6c0d | ||
|
|
33921261f8 | ||
|
|
6f6e2c48ba | ||
|
|
243b222a23 | ||
|
|
35e93db7ff | ||
|
|
b59cbb5fd7 | ||
|
|
cf6ed33ba9 | ||
|
|
bde46e3359 | ||
|
|
2880f24d93 | ||
|
|
c8db0862c1 | ||
|
|
829bd30834 | ||
|
|
bef15a950e | ||
|
|
34be0bc781 | ||
|
|
be7322b3da | ||
|
|
b1c9b3bd38 | ||
|
|
fdb6ab6a1d | ||
|
|
10def637d3 | ||
|
|
fdb65744d4 | ||
|
|
03d35a833c | ||
|
|
dd20f56bc9 | ||
|
|
4df1e07bb9 | ||
|
|
4a3205df84 | ||
|
|
5370f0503a | ||
|
|
e6cbf44d6d | ||
|
|
9bdbf19d54 | ||
|
|
fb9d481e89 | ||
|
|
d619191180 | ||
|
|
63d2a486bf | ||
|
|
8a776122a3 | ||
|
|
d594691a1a | ||
|
|
0a29071b16 | ||
|
|
2d5b7a139f | ||
|
|
07a4b6cbcd | ||
|
|
e3abb63293 | ||
|
|
732c613eeb | ||
|
|
edbb326499 | ||
|
|
4d147c3b16 | ||
|
|
31f96c27a5 | ||
|
|
224b03f9c0 | ||
|
|
8bc370ed38 | ||
|
|
af92f6763d | ||
|
|
6e5e64e27e | ||
|
|
f61194cb86 | ||
|
|
be7f8e0b81 | ||
|
|
0e7904e730 | ||
|
|
6b7c207801 | ||
|
|
3d83e1639e | ||
|
|
a1de176d23 | ||
|
|
399f92cd11 | ||
|
|
8a20d277c5 | ||
|
|
0210695bd9 | ||
|
|
f8914288f0 | ||
|
|
eff7b4f29d | ||
|
|
01809bddff | ||
|
|
6713817e11 | ||
|
|
8ad968f331 | ||
|
|
60a9d2da25 | ||
|
|
c97aa63789 | ||
|
|
594a974ede | ||
|
|
2965da0a5d | ||
|
|
bf1d03a9e5 | ||
|
|
591e0cf08a | ||
|
|
a99a32d3d1 | ||
|
|
c46b49496c | ||
|
|
e310a8e423 | ||
|
|
f7354b43e4 | ||
|
|
1b6422a603 | ||
|
|
366f97b561 | ||
|
|
e5f1a3fb7d | ||
|
|
287aaa9d41 | ||
|
|
3f1f1895ac | ||
|
|
29dcaa2b0a | ||
|
|
ff3be95620 | ||
|
|
7d2bed69ab | ||
|
|
11a8440bc4 | ||
|
|
00a05e357b | ||
|
|
40c836172c | ||
|
|
7eff4e8f3e | ||
|
|
7cb2a2d6c0 | ||
|
|
0f6d1b7efb | ||
|
|
6831c67b8e | ||
|
|
860d07ff89 | ||
|
|
308244a90b | ||
|
|
80853059a9 | ||
|
|
7e619d0be4 | ||
|
|
c70d7226ee | ||
|
|
fd07c22e6e | ||
|
|
93c5328e66 | ||
|
|
c1316a2992 | ||
|
|
c01d11907c | ||
|
|
d464933fd5 | ||
|
|
150591f9e0 | ||
|
|
c9b03fa8af | ||
|
|
9149fd062b | ||
|
|
6d58934791 | ||
|
|
ba1bfef0f2 | ||
|
|
df55695f8e | ||
|
|
5401c4d851 | ||
|
|
86660fef7e | ||
|
|
e0a580b3d0 | ||
|
|
c8b3d4ed3f | ||
|
|
c59bf0007f | ||
|
|
859379e2fc | ||
|
|
abeb762f88 | ||
|
|
14b1e6fe8e | ||
|
|
13dfc532ac | ||
|
|
8d1579cc3c | ||
|
|
8a1e619fb2 | ||
|
|
f84ef1f83c | ||
|
|
b3b3c68a4a | ||
|
|
086ad9ce64 | ||
|
|
516a442f23 | ||
|
|
49dfeda6d7 | ||
|
|
8aa95fa2cd | ||
|
|
de0d144a39 | ||
|
|
4b9f6f407c | ||
|
|
324e532d60 | ||
|
|
5742e321b2 | ||
|
|
c6d630ca81 | ||
|
|
8163de4cc9 | ||
|
|
9d9fc93b70 | ||
|
|
df3f125bd8 | ||
|
|
d100bfcf60 | ||
|
|
ebefbb3d3d | ||
|
|
70e24adaba | ||
|
|
0ad5599229 | ||
|
|
6b05150392 | ||
|
|
926784f513 | ||
|
|
2419bfe34c | ||
|
|
67a69da3aa | ||
|
|
77a4794ed2 | ||
|
|
28365040ac | ||
|
|
65010e97bc | ||
|
|
d18d6d9baf | ||
|
|
269313218d | ||
|
|
edc0b8678b | ||
|
|
24bad4bf1a | ||
|
|
38958f7b3f | ||
|
|
89fa08792e | ||
|
|
963aa30297 | ||
|
|
61016f17d1 | ||
|
|
47d8858c54 | ||
|
|
24dba714cb | ||
|
|
a53bd6f74b | ||
|
|
baabf3bedb | ||
|
|
632c4f21fa | ||
|
|
02271efd89 | ||
|
|
165fa15b0f | ||
|
|
a2badb751f | ||
|
|
5a279e7ae4 | ||
|
|
39837686b0 | ||
|
|
b7bc704f3d | ||
|
|
2a7f37b7b0 | ||
|
|
d4d9a65248 | ||
|
|
b985483c59 | ||
|
|
66560cef74 | ||
|
|
f9b2185586 | ||
|
|
a7cc296714 | ||
|
|
7bb578b1bd | ||
|
|
1f7a1f777d | ||
|
|
0ff3f95d5b | ||
|
|
d5d7284bdd | ||
|
|
f2b00f1048 | ||
|
|
215167d8d3 | ||
|
|
c4f415d979 | ||
|
|
6fbfadc738 | ||
|
|
b301f009e1 | ||
|
|
d03477d4b7 | ||
|
|
ddba8b0e7f | ||
|
|
536e5cecea | ||
|
|
331caf11d3 | ||
|
|
bb29449755 | ||
|
|
c7ae0daf0e | ||
|
|
89facbed88 | ||
|
|
777e25694f | ||
|
|
1539268cf7 | ||
|
|
ff803b1a2a | ||
|
|
cd8adfe418 | ||
|
|
5c8bdcab90 | ||
|
|
c8b7729338 | ||
|
|
cfb631e089 | ||
|
|
93d71b80f2 | ||
|
|
a80bb4e5aa | ||
|
|
16746dd1a6 | ||
|
|
197ffa2be2 | ||
|
|
04b1a52783 | ||
|
|
56b76ce7a8 | ||
|
|
c7d6c667b5 | ||
|
|
93b48e6aba | ||
|
|
8c54b14b5c | ||
|
|
5c7ade2f42 | ||
|
|
e95c34481c | ||
|
|
0c8242b26e | ||
|
|
4b708c4839 | ||
|
|
5e5b8a96a7 | ||
|
|
913858c949 | ||
|
|
30be49c157 | ||
|
|
738d515b95 | ||
|
|
ce25ac172d | ||
|
|
03ee22f342 | ||
|
|
a22b208506 | ||
|
|
8a24da6c10 | ||
|
|
a8ec349198 | ||
|
|
c42725ed54 | ||
|
|
80bbf13959 | ||
|
|
d0fc726988 | ||
|
|
26ed90ab22 | ||
|
|
0e4c4d7efc | ||
|
|
03ee4bbda6 | ||
|
|
7d96ad4d53 | ||
|
|
d67d04c70a | ||
|
|
5710a1e88b | ||
|
|
741b8af31b | ||
|
|
d533b8e922 | ||
|
|
fb443199c1 | ||
|
|
b606e47ddc | ||
|
|
e57bf79616 | ||
|
|
7e6f331233 | ||
|
|
f4a1129e79 | ||
|
|
7df4054b04 | ||
|
|
3f42743d6a | ||
|
|
d7eae8c95c | ||
|
|
8fa62d652b | ||
|
|
077f26af5f | ||
|
|
7f423e8756 | ||
|
|
012f3852bf | ||
|
|
3ec9b9f6b6 | ||
|
|
935bc34dc5 | ||
|
|
9695faf329 | ||
|
|
ab69467697 | ||
|
|
f4cb3f8cac | ||
|
|
9c2c247563 | ||
|
|
c3fbfa8257 | ||
|
|
a09fc9740d | ||
|
|
954aafa064 | ||
|
|
38e043a475 | ||
|
|
be24b3ea83 | ||
|
|
ef85a0d189 | ||
|
|
d5fd26b836 | ||
|
|
2c5ba60269 | ||
|
|
a058233f55 | ||
|
|
03a3b5ffd3 | ||
|
|
8145100da4 | ||
|
|
2b39f09e73 | ||
|
|
d9178320d6 | ||
|
|
d59e951f46 | ||
|
|
e45e4aa97d | ||
|
|
86e5419968 | ||
|
|
4fcd93afb8 | ||
|
|
b0308a7b3a | ||
|
|
c90f0a49f3 | ||
|
|
0438065a20 | ||
|
|
1202e140b9 | ||
|
|
2a2be6a2ce | ||
|
|
2743b674f5 | ||
|
|
58f73d2278 | ||
|
|
054b22c786 | ||
|
|
fd47fea6fb | ||
|
|
0921a6abbc | ||
|
|
f7943db2f3 | ||
|
|
f9679710f1 | ||
|
|
60c36ca841 | ||
|
|
068d37035a | ||
|
|
ef9a4cb60b | ||
|
|
a6fe4dc0c8 | ||
|
|
1dc805dd4d | ||
|
|
9ed36c2eed | ||
|
|
c7f9aa2818 | ||
|
|
14498364f8 | ||
|
|
11e190ef07 | ||
|
|
0847097c29 | ||
|
|
ac9ded338f | ||
|
|
80ce23f6fd | ||
|
|
37565d2ce2 | ||
|
|
3370cbde50 | ||
|
|
33c378f768 | ||
|
|
d51a36397e | ||
|
|
1dbd3a0706 | ||
|
|
887edc431a | ||
|
|
5d8bb1f4a6 | ||
|
|
2d54e3819f | ||
|
|
8660883e1a | ||
|
|
a2e83dbd2a | ||
|
|
0d3ab3198a | ||
|
|
6ab1205580 | ||
|
|
07a199d929 | ||
|
|
382950b701 | ||
|
|
e31211c578 | ||
|
|
e8a5ed9c1c | ||
|
|
98c1dcc6bc | ||
|
|
c2c4fc14d5 | ||
|
|
2daaacef04 | ||
|
|
8a4a1fd70a | ||
|
|
13278d1108 | ||
|
|
5bc5adb627 | ||
|
|
8e9a81a19e | ||
|
|
1e0afd584c | ||
|
|
c7d04beeac | ||
|
|
322f8f18f5 | ||
|
|
affcfd1e52 | ||
|
|
e6779d8437 | ||
|
|
2a8a06e33a | ||
|
|
9d08c6abc2 | ||
|
|
78a7bbdb3b | ||
|
|
a47e863dc5 | ||
|
|
2ef7c5e499 | ||
|
|
845500280d | ||
|
|
956c26d077 | ||
|
|
21b5d353ce | ||
|
|
f8eb7c2858 | ||
|
|
414af7b612 | ||
|
|
4578ab54a5 | ||
|
|
d84dea62de | ||
|
|
ac08920284 | ||
|
|
7393ee8d4f | ||
|
|
5bb2536cc5 | ||
|
|
e4d445c6f5 | ||
|
|
febe0c0faa | ||
|
|
2e5e6ff96c | ||
|
|
1704eacf24 | ||
|
|
a8e1d33ae5 | ||
|
|
91255618dd | ||
|
|
5b71858533 | ||
|
|
a9b5fb3f49 | ||
|
|
0854f82993 | ||
|
|
f29be1e6f7 | ||
|
|
1195155937 | ||
|
|
47fcb1d0b6 | ||
|
|
3dfcb10bef | ||
|
|
80aeba3d5e | ||
|
|
371f1a82c5 | ||
|
|
53defccab7 | ||
|
|
24a7241b5e | ||
|
|
7eb34baf99 | ||
|
|
fe41e39b9b | ||
|
|
ad28e228e3 | ||
|
|
03797b7847 | ||
|
|
db824b5353 | ||
|
|
4d53b31247 | ||
|
|
8174e7236b | ||
|
|
be548690c7 | ||
|
|
f5b13797a6 | ||
|
|
74781d8532 | ||
|
|
0997e843f2 | ||
|
|
68a6701c6d | ||
|
|
2fb3bb31ef | ||
|
|
176ac6ab09 | ||
|
|
67a42103d9 | ||
|
|
7699bd733b | ||
|
|
606135dd98 | ||
|
|
108c60f460 | ||
|
|
8be93c23ee | ||
|
|
6d0c0994e9 | ||
|
|
c39ff9978d | ||
|
|
3bd58fac7b | ||
|
|
956907a4b1 | ||
|
|
ed535649d4 | ||
|
|
d459afa8db | ||
|
|
410be197ef | ||
|
|
e2209f7534 | ||
|
|
5295a683f9 | ||
|
|
4d63b472f2 | ||
|
|
7c4512cbeb | ||
|
|
cfae9c2eaf | ||
|
|
7024745a14 | ||
|
|
0127ac668e | ||
|
|
d57e5edbcd | ||
|
|
03e47a8255 | ||
|
|
8712ef2f81 | ||
|
|
e0a8030048 | ||
|
|
e4bfe2aa4b | ||
|
|
acda2e7d0b | ||
|
|
871330c379 | ||
|
|
b653fedca5 | ||
|
|
3f8f1f16bd | ||
|
|
ba1e959e53 | ||
|
|
d14a4b480c | ||
|
|
ceeb033054 | ||
|
|
10cacef2c0 | ||
|
|
e1129b2d3e | ||
|
|
b00b430e87 | ||
|
|
39517d1046 | ||
|
|
44420423de | ||
|
|
88749550f6 | ||
|
|
5198b1de31 | ||
|
|
669a42c604 | ||
|
|
a7d7941d3e | ||
|
|
e99dbe141d | ||
|
|
51870ddaef | ||
|
|
838ce5bbad | ||
|
|
69fcabb335 | ||
|
|
292f5bec1c | ||
|
|
dd6110eed3 | ||
|
|
d8efa2257e | ||
|
|
2e52f87763 | ||
|
|
4f51fa947f | ||
|
|
7d268d4bcb | ||
|
|
2997d3910d | ||
|
|
d73ffaafe6 | ||
|
|
5ab9ab7940 | ||
|
|
3180f15837 | ||
|
|
0a5dcdc2c4 | ||
|
|
a0612a4d34 | ||
|
|
47e775be2b | ||
|
|
6de3d490a2 | ||
|
|
a87b3c2101 | ||
|
|
efca4af936 |
@@ -0,0 +1,27 @@
|
||||
<!-- Provide a general summary of your proposed changes in the Title field above -->
|
||||
|
||||
### Description
|
||||
<!-- Describe your changes in detail -->
|
||||
|
||||
### Checklist
|
||||
<!-- go over following points. check them with an `x` if they do apply, (they turn into clickable checkboxes once the PR is submitted, so no need to do everything at once)
|
||||
|
||||
-->
|
||||
|
||||
This pull request is:
|
||||
|
||||
- [ ] A documentation / typographical error fix
|
||||
- Good to go, no issue or tests are needed
|
||||
- [ ] A short code fix
|
||||
- please include the issue number, and create an issue if none exists, which
|
||||
must include a complete example of the issue. one line code fixes without an
|
||||
issue and demonstration will not be accepted.
|
||||
- Please include: `Fixes: #<issue number>` in the commit message
|
||||
- please include tests. one line code fixes without tests will not be accepted.
|
||||
- [ ] A new feature implementation
|
||||
- please include the issue number, and create an issue if none exists, which must
|
||||
include a complete example of how the feature would look.
|
||||
- Please include: `Fixes: #<issue number>` in the commit message
|
||||
- please include tests.
|
||||
|
||||
**Have a nice day!**
|
||||
+11
@@ -19,3 +19,14 @@ coverage.xml
|
||||
sqlnet.log
|
||||
/mapping_setup.py
|
||||
/test.py
|
||||
/.cache/
|
||||
/.mypy_cache
|
||||
*.sw[o,p]
|
||||
/test?.py
|
||||
/test.py
|
||||
/mapping_setup.py
|
||||
*.rej
|
||||
test/test_schema.db
|
||||
*test_schema.db
|
||||
.idea
|
||||
/Pipfile*
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
[gerrit]
|
||||
host=gerrit.sqlalchemy.org
|
||||
project=sqlalchemy/sqlalchemy
|
||||
defaultbranch=master
|
||||
@@ -12,7 +12,4 @@ Major contributing authors include:
|
||||
- Paul Johnston <paj@pajhome.org.uk>
|
||||
- Jonathan Ellis <jbellis@gmail.com>
|
||||
|
||||
For a larger list of SQLAlchemy contributors over time, see:
|
||||
|
||||
http://www.sqlalchemy.org/trac/wiki/Contributors
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
This is the MIT license: http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
Copyright (c) 2005-2015 the SQLAlchemy authors and contributors <see AUTHORS file>.
|
||||
Copyright (c) 2005-2019 the SQLAlchemy authors and contributors <see AUTHORS file>.
|
||||
SQLAlchemy is a trademark of Michael Bayer.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
# any kind of "*" pulls in __init__.pyc files,
|
||||
# so all extensions are explicit.
|
||||
|
||||
recursive-include doc *.html *.css *.txt *.js *.jpg *.png *.py Makefile *.rst *.mako *.sty
|
||||
recursive-include doc *.html *.css *.txt *.js *.png *.py Makefile *.rst *.sty
|
||||
recursive-include examples *.py *.xml
|
||||
recursive-include test *.py *.dat
|
||||
|
||||
@@ -9,5 +9,5 @@ recursive-include test *.py *.dat
|
||||
# don't come in if --with-cextensions isn't specified.
|
||||
recursive-include lib *.c *.txt
|
||||
|
||||
include README* AUTHORS LICENSE distribute_setup.py sa2to3.py ez_setup.py sqla_nose.py CHANGES* tox.ini
|
||||
include README* AUTHORS LICENSE sqla_nose.py CHANGES* tox.ini
|
||||
prune doc/build/output
|
||||
|
||||
+5
-57
@@ -35,7 +35,6 @@ The file structure of a dialect is typically similar to the following::
|
||||
sqlalchemy-<dialect>/
|
||||
setup.py
|
||||
setup.cfg
|
||||
run_tests.py
|
||||
sqlalchemy_<dialect>/
|
||||
__init__.py
|
||||
base.py
|
||||
@@ -77,27 +76,20 @@ Key aspects of this file layout include:
|
||||
[egg_info]
|
||||
tag_build = dev
|
||||
|
||||
[pytest]
|
||||
addopts= --tb native -v -r fxX
|
||||
[tool:pytest]
|
||||
addopts= --tb native -v -r fxX --maxfail=25 -p no:warnings
|
||||
python_files=test/*test_*.py
|
||||
|
||||
[nosetests]
|
||||
with-sqla_testing = true
|
||||
where = test
|
||||
cover-package = sqlalchemy_access
|
||||
with-coverage = 1
|
||||
cover-erase = 1
|
||||
|
||||
[sqla_testing]
|
||||
requirement_cls=sqlalchemy_access.requirements:Requirements
|
||||
profile_file=.profiles.txt
|
||||
profile_file=test/profiles.txt
|
||||
|
||||
[db]
|
||||
default=access+pyodbc://admin@access_test
|
||||
sqlite=sqlite:///:memory:
|
||||
|
||||
Above, the ``[sqla_testing]`` section contains configuration used by
|
||||
SQLAlchemy's test plugin. The ``[pytest]`` and ``[nosetests]`` sections
|
||||
SQLAlchemy's test plugin. The ``[tool:pytest]`` section
|
||||
include directives to help with these runners; in the case of
|
||||
Nose, the directive ``with-sql_testing = true``, which indicates to Nose that
|
||||
the SQLAlchemy nose plugin should be used. In the case of pytest, the
|
||||
@@ -122,35 +114,6 @@ Key aspects of this file layout include:
|
||||
of setuptools, using the ``registry.register()`` function in a way that
|
||||
is similar to the ``entry_points`` directive we placed in our ``setup.py``.
|
||||
|
||||
* run_tests.py - This script is used when running the tests via Nose.
|
||||
The purpose of the script is to plug in SQLAlchemy's nose plugin into
|
||||
the Nose environment before the tests run.
|
||||
|
||||
The format of this file is similar to that of conftest.py; first,
|
||||
the optional but helpful step of registering your third party plugin,
|
||||
then the other is to import SQLAlchemy's nose runner and invoke it::
|
||||
|
||||
from sqlalchemy.dialects import registry
|
||||
|
||||
registry.register("access", "sqlalchemy_access.pyodbc", "AccessDialect_pyodbc")
|
||||
registry.register("access.pyodbc", "sqlalchemy_access.pyodbc", "AccessDialect_pyodbc")
|
||||
|
||||
from sqlalchemy.testing import runner
|
||||
|
||||
# use this in setup.py 'test_suite':
|
||||
# test_suite="run_tests.setup_py_test"
|
||||
def setup_py_test():
|
||||
runner.setup_py_test()
|
||||
|
||||
if __name__ == '__main__':
|
||||
runner.main()
|
||||
|
||||
The call to ``runner.main()`` then runs the Nose front end, which installs
|
||||
SQLAlchemy's testing plugins. Invoking our custom runner looks like the
|
||||
following::
|
||||
|
||||
$ python run_tests.py -v
|
||||
|
||||
* requirements.py - The ``requirements.py`` file is where directives
|
||||
regarding database and dialect capabilities are set up.
|
||||
SQLAlchemy's tests are often annotated with decorators that mark
|
||||
@@ -229,7 +192,7 @@ Going Forward
|
||||
==============
|
||||
|
||||
The third-party dialect can be distributed like any other Python
|
||||
module on Pypi. Links to prominent dialects can be featured within
|
||||
module on PyPI. Links to prominent dialects can be featured within
|
||||
SQLAlchemy's own documentation; contact the developers (see AUTHORS)
|
||||
for help with this.
|
||||
|
||||
@@ -245,18 +208,3 @@ requirements file will receive new tests and changes. The dialect
|
||||
maintainer would normally keep track of these changes and make
|
||||
adjustments as needed.
|
||||
|
||||
Continuous Integration
|
||||
======================
|
||||
|
||||
The most ideal scenario for ongoing dialect testing is continuous
|
||||
integration, that is, an automated test runner that runs in response
|
||||
to changes not just in the dialect itself but to new pushes to
|
||||
SQLAlchemy as well.
|
||||
|
||||
The SQLAlchemy project features a Jenkins installation that runs tests
|
||||
on Amazon EC2 instances. It is possible for third-party dialect
|
||||
developers to provide the SQLAlchemy project either with AMIs or EC2
|
||||
instance keys which feature test environments appropriate to the
|
||||
dialect - SQLAlchemy's own Jenkins suite can invoke tests on these
|
||||
environments. Contact the developers for further info.
|
||||
|
||||
|
||||
+31
-23
@@ -16,47 +16,47 @@ language.
|
||||
|
||||
Major SQLAlchemy features include:
|
||||
|
||||
* An industrial strength ORM, built
|
||||
* An industrial strength ORM, built
|
||||
from the core on the identity map, unit of work,
|
||||
and data mapper patterns. These patterns
|
||||
allow transparent persistence of objects
|
||||
allow transparent persistence of objects
|
||||
using a declarative configuration system.
|
||||
Domain models
|
||||
can be constructed and manipulated naturally,
|
||||
and changes are synchronized with the
|
||||
current transaction automatically.
|
||||
* A relationally-oriented query system, exposing
|
||||
the full range of SQL's capabilities
|
||||
explicitly, including joins, subqueries,
|
||||
correlation, and most everything else,
|
||||
the full range of SQL's capabilities
|
||||
explicitly, including joins, subqueries,
|
||||
correlation, and most everything else,
|
||||
in terms of the object model.
|
||||
Writing queries with the ORM uses the same
|
||||
techniques of relational composition you use
|
||||
Writing queries with the ORM uses the same
|
||||
techniques of relational composition you use
|
||||
when writing SQL. While you can drop into
|
||||
literal SQL at any time, it's virtually never
|
||||
needed.
|
||||
* A comprehensive and flexible system
|
||||
* A comprehensive and flexible system
|
||||
of eager loading for related collections and objects.
|
||||
Collections are cached within a session,
|
||||
and can be loaded on individual access, all
|
||||
and can be loaded on individual access, all
|
||||
at once using joins, or by query per collection
|
||||
across the full result set.
|
||||
* A Core SQL construction system and DBAPI
|
||||
* A Core SQL construction system and DBAPI
|
||||
interaction layer. The SQLAlchemy Core is
|
||||
separate from the ORM and is a full database
|
||||
abstraction layer in its own right, and includes
|
||||
an extensible Python-based SQL expression
|
||||
language, schema metadata, connection pooling,
|
||||
an extensible Python-based SQL expression
|
||||
language, schema metadata, connection pooling,
|
||||
type coercion, and custom types.
|
||||
* All primary and foreign key constraints are
|
||||
* All primary and foreign key constraints are
|
||||
assumed to be composite and natural. Surrogate
|
||||
integer primary keys are of course still the
|
||||
integer primary keys are of course still the
|
||||
norm, but SQLAlchemy never assumes or hardcodes
|
||||
to this model.
|
||||
* Database introspection and generation. Database
|
||||
schemas can be "reflected" in one step into
|
||||
Python structures representing database metadata;
|
||||
those same structures can then generate
|
||||
those same structures can then generate
|
||||
CREATE statements right back out - all within
|
||||
the Core, independent of the ORM.
|
||||
|
||||
@@ -73,7 +73,7 @@ SQLAlchemy's philosophy:
|
||||
that should be fully exposed. SQLAlchemy's
|
||||
ORM provides an open-ended set of patterns
|
||||
that allow a developer to construct a custom
|
||||
mediation layer between a domain model and
|
||||
mediation layer between a domain model and
|
||||
a relational schema, turning the so-called
|
||||
"object relational impedance" issue into
|
||||
a distant memory.
|
||||
@@ -82,18 +82,18 @@ SQLAlchemy's philosophy:
|
||||
of both the object model as well as the relational
|
||||
schema. SQLAlchemy only provides the means
|
||||
to automate the execution of these decisions.
|
||||
* With SQLAlchemy, there's no such thing as
|
||||
"the ORM generated a bad query" - you
|
||||
retain full control over the structure of
|
||||
* With SQLAlchemy, there's no such thing as
|
||||
"the ORM generated a bad query" - you
|
||||
retain full control over the structure of
|
||||
queries, including how joins are organized,
|
||||
how subqueries and correlation is used, what
|
||||
how subqueries and correlation is used, what
|
||||
columns are requested. Everything SQLAlchemy
|
||||
does is ultimately the result of a developer-
|
||||
initiated decision.
|
||||
* Don't use an ORM if the problem doesn't need one.
|
||||
SQLAlchemy consists of a Core and separate ORM
|
||||
component. The Core offers a full SQL expression
|
||||
language that allows Pythonic construction
|
||||
language that allows Pythonic construction
|
||||
of SQL constructs that render directly to SQL
|
||||
strings for a target database, returning
|
||||
result sets that are essentially enhanced DBAPI
|
||||
@@ -105,7 +105,7 @@ SQLAlchemy's philosophy:
|
||||
the start and end of a series of operations.
|
||||
* Never render a literal value in a SQL statement.
|
||||
Bound parameters are used to the greatest degree
|
||||
possible, allowing query optimizers to cache
|
||||
possible, allowing query optimizers to cache
|
||||
query plans effectively and making SQL injection
|
||||
attacks a non-issue.
|
||||
|
||||
@@ -119,7 +119,7 @@ http://www.sqlalchemy.org/docs/
|
||||
Installation / Requirements
|
||||
---------------------------
|
||||
|
||||
Full documentation for installation is at
|
||||
Full documentation for installation is at
|
||||
`Installation <http://www.sqlalchemy.org/docs/intro.html#installation>`_.
|
||||
|
||||
Getting Help / Development / Bug reporting
|
||||
@@ -127,6 +127,14 @@ Getting Help / Development / Bug reporting
|
||||
|
||||
Please refer to the `SQLAlchemy Community Guide <http://www.sqlalchemy.org/support.html>`_.
|
||||
|
||||
Code of Conduct
|
||||
---------------
|
||||
|
||||
Above all, SQLAlchemy places great emphasis on polite, thoughtful, and
|
||||
constructive communication between users and developers.
|
||||
Please see our current Code of Conduct at
|
||||
`Code of Conduct <http://www.sqlalchemy.org/codeofconduct.html>`_.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
|
||||
+118
-247
@@ -2,193 +2,146 @@
|
||||
SQLALCHEMY UNIT TESTS
|
||||
=====================
|
||||
|
||||
**NOTE:** SQLAlchemy as of 0.9.4 now standardizes on `pytest <http://pytest.org/>`_
|
||||
for test running! However, the existing support for Nose **still remains**!
|
||||
That is, you can now run the tests via pytest or nose. We hope to keep the
|
||||
suite nose-compatible indefinitely however this might change at some point.
|
||||
Updated for 1.1, 1.2
|
||||
|
||||
SQLAlchemy unit tests by default run using Python's built-in sqlite3
|
||||
module. If running on a Python installation that doesn't include this
|
||||
module, then pysqlite or compatible must be installed.
|
||||
Basic Test Running
|
||||
==================
|
||||
|
||||
Unit tests can be run with pytest or nose:
|
||||
A test target exists within the setup.py script. For basic test runs::
|
||||
|
||||
py.test: http://pytest.org/
|
||||
|
||||
nose: https://pypi.python.org/pypi/nose/
|
||||
|
||||
The suite includes enhanced support when running with pytest.
|
||||
|
||||
SQLAlchemy implements plugins for both pytest and nose that must be
|
||||
present when tests are run. In the case of pytest, this plugin is automatically
|
||||
used when pytest is run against the SQLAlchemy source tree. However,
|
||||
for Nose support, a special test runner script must be used.
|
||||
python setup.py test
|
||||
|
||||
|
||||
The test suite as also requires the mock library. While
|
||||
mock is part of the Python standard library as of 3.3, previous versions
|
||||
will need to have it installed, and is available at::
|
||||
Running with Tox
|
||||
================
|
||||
|
||||
https://pypi.python.org/pypi/mock
|
||||
For more elaborate CI-style test running, the tox script provided will
|
||||
run against various Python / database targets. For a basic run against
|
||||
Python 2.7 using an in-memory SQLite database::
|
||||
|
||||
RUNNING TESTS VIA SETUP.PY
|
||||
--------------------------
|
||||
A plain vanilla run of all tests using sqlite can be run via setup.py, and
|
||||
requires that pytest is installed::
|
||||
tox -e py27-sqlite
|
||||
|
||||
$ python setup.py test
|
||||
The tox runner contains a series of target combinations that can run
|
||||
against various combinations of databases. The test suite can be
|
||||
run against SQLite with "backend" tests also running against a PostgreSQL
|
||||
database::
|
||||
|
||||
tox -e py36-sqlite-postgresql
|
||||
|
||||
Or to run just "backend" tests against a MySQL database::
|
||||
|
||||
tox -e py36-mysql-backendonly
|
||||
|
||||
Running against backends other than SQLite requires that a database of that
|
||||
vendor be available at a specific URL. See "Setting Up Databases" below
|
||||
for details.
|
||||
|
||||
The py.test Engine
|
||||
==================
|
||||
|
||||
Both the tox runner and the setup.py runner are using py.test to invoke
|
||||
the test suite. Within the realm of py.test, SQLAlchemy itself is adding
|
||||
a large series of option and customizations to the py.test runner using
|
||||
plugin points, to allow for SQLAlchemy's multiple database support,
|
||||
database setup/teardown and connectivity, multi process support, as well as
|
||||
lots of skip / database selection rules.
|
||||
|
||||
Running tests with py.test directly grants more immediate control over
|
||||
database options and test selection.
|
||||
|
||||
A generic py.test run looks like::
|
||||
|
||||
py.test -n4
|
||||
|
||||
Above, the full test suite will run against SQLite, using four processes.
|
||||
If the "-n" flag is not used, the pytest-xdist is skipped and the tests will
|
||||
run linearly, which will take a pretty long time.
|
||||
|
||||
The py.test command line is more handy for running subsets of tests and to
|
||||
quickly allow for custom database connections. Example::
|
||||
|
||||
py.test --dburi=postgresql+psycopg2://scott:tiger@localhost/test test/sql/test_query.py
|
||||
|
||||
Above will run the tests in the test/sql/test_query.py file (a pretty good
|
||||
file for basic "does this database work at all?" to start with) against a
|
||||
running PostgreSQL database at the given URL.
|
||||
|
||||
The py.test frontend can also run tests against multiple kinds of databases
|
||||
at once - a large subset of tests are marked as "backend" tests, which will
|
||||
be run against each available backend, and additionally lots of tests are targeted
|
||||
at specific backends only, which only run if a matching backend is made available.
|
||||
For example, to run the test suite against both PostgreSQL and MySQL at the same time::
|
||||
|
||||
py.test -n4 --db postgresql --db mysql
|
||||
|
||||
|
||||
RUNNING ALL TESTS - PYTEST
|
||||
--------------------------
|
||||
To run all tests::
|
||||
Setting Up Databases
|
||||
====================
|
||||
|
||||
$ py.test
|
||||
The test suite identifies several built-in database tags that run against
|
||||
a pre-set URL. These can be seen using --dbs::
|
||||
|
||||
The pytest configuration in setup.cfg will point the runner at the
|
||||
test/ directory, where it consumes a conftest.py file that gets everything
|
||||
else up and running.
|
||||
|
||||
|
||||
RUNNING ALL TESTS - NOSE
|
||||
--------------------------
|
||||
|
||||
When using Nose, a bootstrap script is provided which sets up sys.path
|
||||
as well as installs the nose plugin::
|
||||
|
||||
$ ./sqla_nose.py
|
||||
|
||||
Assuming all tests pass, this is a very unexciting output. To make it more
|
||||
interesting::
|
||||
|
||||
$ ./sqla_nose.py -v
|
||||
|
||||
RUNNING INDIVIDUAL TESTS
|
||||
---------------------------------
|
||||
|
||||
Any directory of test modules can be run at once by specifying the directory
|
||||
path, and a specific file can be specified as well::
|
||||
|
||||
$ py.test test/dialect
|
||||
|
||||
$ py.test test/orm/test_mapper.py
|
||||
|
||||
When using nose, the setup.cfg currently sets "where" to "test/", so the
|
||||
"test/" prefix is omitted::
|
||||
|
||||
$ ./sqla_nose.py dialect/
|
||||
|
||||
$ ./sqla_nose.py orm/test_mapper.py
|
||||
|
||||
With Nose, it is often more intuitive to specify tests as module paths::
|
||||
|
||||
$ ./sqla_nose.py test.orm.test_mapper
|
||||
|
||||
Nose can also specify a test class and optional method using this syntax::
|
||||
|
||||
$ ./sqla_nose.py test.orm.test_mapper:MapperTest.test_utils
|
||||
|
||||
With pytest, the -k flag is used to limit tests::
|
||||
|
||||
$ py.test test/orm/test_mapper.py -k "MapperTest and test_utils"
|
||||
|
||||
|
||||
COMMAND LINE OPTIONS
|
||||
--------------------
|
||||
|
||||
SQLAlchemy-specific options are added to both runners, which are viewable
|
||||
within the help screen. With pytest, these options are easier to locate
|
||||
as they are underneath the "sqlalchemy" grouping::
|
||||
|
||||
$ py.test --help
|
||||
|
||||
$ ./sqla_nose.py --help
|
||||
|
||||
The --help screen is a combination of common nose options and options which
|
||||
the SQLAlchemy nose plugin adds. The most commonly SQLAlchemy-specific
|
||||
options used are '--db' and '--dburi'.
|
||||
|
||||
Both pytest and nose support the same set of SQLAlchemy options, though
|
||||
pytest features a bit more capability with them.
|
||||
|
||||
|
||||
DATABASE TARGETS
|
||||
----------------
|
||||
|
||||
Tests will target an in-memory SQLite database by default. To test against
|
||||
another database, use the --dburi option with any standard SQLAlchemy URL::
|
||||
|
||||
--dburi=postgresql://user:password@localhost/test
|
||||
|
||||
If you'll be running the tests frequently, database aliases can save a lot of
|
||||
typing. The --dbs option lists the built-in aliases and their matching URLs::
|
||||
|
||||
$ py.test --dbs
|
||||
$ py.test --dbs=.
|
||||
Available --db options (use --dburi to override)
|
||||
mysql mysql://scott:tiger@127.0.0.1:3306/test
|
||||
oracle oracle://scott:tiger@127.0.0.1:1521
|
||||
postgresql postgresql://scott:tiger@127.0.0.1:5432/test
|
||||
[...]
|
||||
default sqlite:///:memory:
|
||||
firebird firebird://sysdba:masterkey@localhost//Users/classic/foo.fdb
|
||||
mssql mssql+pyodbc://scott:tiger@ms_2008
|
||||
mssql_pymssql mssql+pymssql://scott:tiger@ms_2008
|
||||
mysql mysql://scott:tiger@127.0.0.1:3306/test?charset=utf8
|
||||
oracle oracle://scott:tiger@127.0.0.1:1521
|
||||
oracle8 oracle://scott:tiger@127.0.0.1:1521/?use_ansi=0
|
||||
pg8000 postgresql+pg8000://scott:tiger@127.0.0.1:5432/test
|
||||
postgresql postgresql://scott:tiger@127.0.0.1:5432/test
|
||||
postgresql_psycopg2cffi postgresql+psycopg2cffi://scott:tiger@127.0.0.1:5432/test
|
||||
pymysql mysql+pymysql://scott:tiger@127.0.0.1:3306/test?charset=utf8
|
||||
sqlite sqlite:///:memory:
|
||||
sqlite_file sqlite:///querytest.db
|
||||
|
||||
To run tests against an aliased database::
|
||||
What those mean is that if you have a database running that can be accessed
|
||||
by the above URL, you can run the test suite against it using ``--db <name>``.
|
||||
|
||||
$ py.test --db postgresql
|
||||
|
||||
This list of database urls is present in the setup.cfg file. The list
|
||||
can be modified/extended by adding a file ``test.cfg`` at the
|
||||
top level of the SQLAlchemy source distribution which includes
|
||||
additional entries::
|
||||
The URLs are present in the ``setup.cfg`` file. You can make your own URLs by
|
||||
creating a new file called ``test.cfg`` and adding your own ``[db]`` section::
|
||||
|
||||
# test.cfg file
|
||||
[db]
|
||||
postgresql=postgresql://myuser:mypass@localhost/mydb
|
||||
my_postgresql=postgresql://username:pass@hostname/dbname
|
||||
|
||||
Your custom entries will override the defaults and you'll see them reflected
|
||||
in the output of --dbs.
|
||||
Above, we can now run the tests with ``my_postgresql``::
|
||||
|
||||
MULTIPLE DATABASE TARGETS
|
||||
-------------------------
|
||||
py.test --db my_postgresql
|
||||
|
||||
As of SQLAlchemy 0.9.4, the test runner supports **multiple databases at once**.
|
||||
This doesn't mean that the entire test suite runs for each database, but
|
||||
instead specific test suites may do so, while other tests may choose to
|
||||
run on a specific target out of those available. For example, if the tests underneath
|
||||
test/dialect/ are run, the majority of these tests are either specific to
|
||||
a particular backend, or are marked as "multiple", meaning they will run repeatedly
|
||||
for each database in use. If one runs the test suite as follows::
|
||||
We can also override the existing names in our ``test.cfg`` file, so that we can run
|
||||
with the tox runner also::
|
||||
|
||||
$ py.test test/dialect --db sqlite --db postgresql --db mysql
|
||||
# test.cfg file
|
||||
[db]
|
||||
postgresql=postgresql://username:pass@hostname/dbname
|
||||
|
||||
The tests underneath test/dialect/test_suite.py will be tripled up, running
|
||||
as appropriate for each target database, whereas dialect-specific tests
|
||||
within test/dialect/mysql, test/dialect/postgresql/ test/dialect/test_sqlite.py
|
||||
should run fully with no skips, as each suite has its target database available.
|
||||
Now when we run ``tox -e py27-postgresql``, it will use our custom URL instead
|
||||
of the fixed one in setup.cfg.
|
||||
|
||||
The multiple targets feature is available both under pytest and nose,
|
||||
however when running nose, the "multiple runner" feature won't be available;
|
||||
instead, the first database target will be used.
|
||||
Database Configuration
|
||||
======================
|
||||
|
||||
When running with multiple targets, tests that don't prefer a specific target
|
||||
will be run against the first target specified. Putting sqlite first in
|
||||
the list will lead to a much faster suite as the in-memory database is
|
||||
extremely fast for setting up and tearing down tables.
|
||||
|
||||
|
||||
|
||||
DATABASE CONFIGURATION
|
||||
----------------------
|
||||
|
||||
Use an empty database and a database user with general DBA privileges.
|
||||
The test suite will be creating and dropping many tables and other DDL, and
|
||||
preexisting tables will interfere with the tests.
|
||||
The test runner will by default create and drop tables within the default
|
||||
database that's in the database URL, *unless* the multiprocessing option
|
||||
is in use via the py.test "-n" flag, which invokes pytest-xdist. The
|
||||
multiprocessing option is **enabled by default** for both the tox runner
|
||||
and the setup.py frontend. When multiprocessing is used, the SQLAlchemy
|
||||
testing framework will create a new database for each process, and then
|
||||
tear it down after the test run is complete. So it will be necessary
|
||||
for the database user to have access to CREATE DATABASE in order for this
|
||||
to work.
|
||||
|
||||
Several tests require alternate usernames or schemas to be present, which
|
||||
are used to test dotted-name access scenarios. On some databases such
|
||||
as Oracle or Sybase, these are usernames, and others such as Postgresql
|
||||
as Oracle or Sybase, these are usernames, and others such as PostgreSQL
|
||||
and MySQL they are schemas. The requirement applies to all backends
|
||||
except SQLite and Firebird. The names are::
|
||||
|
||||
test_schema
|
||||
test_schema_2 (only used on Postgresql)
|
||||
test_schema_2 (only used on PostgreSQL)
|
||||
|
||||
Please refer to your vendor documentation for the proper syntax to create
|
||||
these namespaces - the database user must have permission to create and drop
|
||||
@@ -210,10 +163,14 @@ Additional steps specific to individual databases are as follows::
|
||||
test=# create extension hstore;
|
||||
CREATE EXTENSION
|
||||
|
||||
MYSQL: Default storage engine should be "MyISAM". Tests that require
|
||||
"InnoDB" as the engine will specify this explicitly.
|
||||
Full-text search configuration should be set to English, else
|
||||
several tests of ``.match()`` will fail. This can be set (if it isn't so
|
||||
already) with:
|
||||
|
||||
ORACLE: a user named "test_schema" is created.
|
||||
ALTER DATABASE test SET default_text_search_config = 'pg_catalog.english'
|
||||
|
||||
ORACLE: a user named "test_schema" is created in addition to the default
|
||||
user.
|
||||
|
||||
The primary database user needs to be able to create and drop tables,
|
||||
synonyms, and constraints within the "test_schema" user. For this
|
||||
@@ -223,31 +180,6 @@ Additional steps specific to individual databases are as follows::
|
||||
|
||||
grant dba to scott;
|
||||
|
||||
SYBASE: Similar to Oracle, "test_schema" is created as a user, and the
|
||||
primary test user needs to have the "sa_role".
|
||||
|
||||
It's also recommended to turn on "trunc log on chkpt" and to use a
|
||||
separate transaction log device - Sybase basically seizes up when
|
||||
the transaction log is full otherwise.
|
||||
|
||||
A full series of setup assuming sa/master:
|
||||
|
||||
disk init name="translog", physname="/opt/sybase/data/translog.dat", size="10M"
|
||||
create database sqlalchemy on default log on translog="10M"
|
||||
sp_dboption sqlalchemy, "trunc log on chkpt", true
|
||||
sp_addlogin scott, "tiger7"
|
||||
sp_addlogin test_schema, "tiger7"
|
||||
use sqlalchemy
|
||||
sp_adduser scott
|
||||
sp_adduser test_schema
|
||||
grant all to scott
|
||||
sp_role "grant", sa_role, scott
|
||||
|
||||
Sybase will still freeze for up to a minute when the log becomes
|
||||
full. To manually dump the log::
|
||||
|
||||
dump tran sqlalchemy with truncate_only
|
||||
|
||||
MSSQL: Tests that involve multiple connections require Snapshot Isolation
|
||||
ability implemented on the test database in order to prevent deadlocks that
|
||||
will occur with record locking isolation. This feature is only available
|
||||
@@ -258,16 +190,6 @@ Additional steps specific to individual databases are as follows::
|
||||
|
||||
ALTER DATABASE MyDatabase SET READ_COMMITTED_SNAPSHOT ON
|
||||
|
||||
MSSQL+zxJDBC: Trying to run the unit tests on Windows against SQL Server
|
||||
requires using a test.cfg configuration file as the cmd.exe shell won't
|
||||
properly pass the URL arguments into the nose test runner.
|
||||
|
||||
POSTGRESQL: Full-text search configuration should be set to English, else
|
||||
several tests of ``.match()`` will fail. This can be set (if it isn't so
|
||||
already) with:
|
||||
|
||||
ALTER DATABASE test SET default_text_search_config = 'pg_catalog.english'
|
||||
|
||||
|
||||
CONFIGURING LOGGING
|
||||
-------------------
|
||||
@@ -275,66 +197,15 @@ SQLAlchemy logs its activity and debugging through Python's logging package.
|
||||
Any log target can be directed to the console with command line options, such
|
||||
as::
|
||||
|
||||
$ ./sqla_nose.py test.orm.unitofwork --log-info=sqlalchemy.orm.mapper \
|
||||
$ ./py.test test/orm/test_unitofwork.py -s \
|
||||
--log-debug=sqlalchemy.pool --log-info=sqlalchemy.engine
|
||||
|
||||
This would log mapper configuration, connection pool checkouts, and SQL
|
||||
statement execution.
|
||||
Above we add the py.test "-s" flag so that standard out is not suppressed.
|
||||
|
||||
|
||||
BUILT-IN COVERAGE REPORTING
|
||||
------------------------------
|
||||
Coverage is tracked using the coverage plugins built for pytest or nose::
|
||||
|
||||
$ py.test test/sql/test_query --cov=sqlalchemy
|
||||
|
||||
$ ./sqla_nose.py test.sql.test_query --with-coverage
|
||||
|
||||
BIG COVERAGE TIP !!! There is an issue where existing .pyc files may
|
||||
store the incorrect filepaths, which will break the coverage system. If
|
||||
coverage numbers are coming out as low/zero, try deleting all .pyc files.
|
||||
|
||||
DEVELOPING AND TESTING NEW DIALECTS
|
||||
-----------------------------------
|
||||
|
||||
See the file README.dialects.rst for detail on dialects.
|
||||
|
||||
|
||||
TESTING WITH MULTIPLE PYTHON VERSIONS USING TOX
|
||||
-----------------------------------------------
|
||||
|
||||
If you want to test across multiple versions of Python, you may find `tox
|
||||
<http://tox.testrun.org/>`_ useful. SQLAlchemy includes a tox.ini file::
|
||||
|
||||
tox -e full
|
||||
|
||||
SQLAlchemy uses tox mostly for pre-fab testing configurations, to simplify
|
||||
configuration of Jenkins jobs, and *not* for testing different Python
|
||||
interpreters simultaneously. You can of course create whatever alternate
|
||||
tox.ini file you want.
|
||||
|
||||
Environments include::
|
||||
|
||||
"full" - runs a full py.test
|
||||
|
||||
"coverage" - runs a py.test plus coverage, skipping memory/timing
|
||||
intensive tests
|
||||
|
||||
"pep8" - runs flake8 against the codebase (useful with --diff to check
|
||||
against a patch)
|
||||
|
||||
|
||||
PARALLEL TESTING
|
||||
----------------
|
||||
|
||||
Parallel testing is supported using the Pytest xdist plugin. Supported
|
||||
databases currently include sqlite, postgresql, and mysql. The username
|
||||
for the database should have CREATE DATABASE and DROP DATABASE privileges.
|
||||
After installing pytest-xdist, testing is run adding the -n<num> option.
|
||||
For example, to run against sqlite, mysql, postgresql with four processes::
|
||||
|
||||
tox -e -- -n 4 --db sqlite --db postgresql --db mysql
|
||||
|
||||
Each backend has a different scheme for setting up the database. Postgresql
|
||||
still needs the "test_schema" and "test_schema_2" schemas present, as the
|
||||
parallel databases are created using the base database as a "template".
|
||||
|
||||
Vendored
+6
-6
@@ -1,7 +1,7 @@
|
||||
|
||||
==============
|
||||
=============
|
||||
0.1 Changelog
|
||||
==============
|
||||
=============
|
||||
|
||||
|
||||
.. changelog::
|
||||
@@ -223,7 +223,7 @@
|
||||
added 'version_id' keyword argument to mapper. this keyword should reference a
|
||||
Column object with type Integer, preferably non-nullable, which will be used on
|
||||
the mapped table to track version numbers. this number is incremented on each
|
||||
save operation and is specifed in the UPDATE/DELETE conditions so that it
|
||||
save operation and is specified in the UPDATE/DELETE conditions so that it
|
||||
factors into the returned row count, which results in a ConcurrencyError if the
|
||||
value received is not the expected count.
|
||||
|
||||
@@ -237,7 +237,7 @@
|
||||
created for a class, qualified by the entity name. instances of those classes
|
||||
will issue all of their load and save operations through their
|
||||
entity_name-qualified mapper, and maintain separate a identity in the identity
|
||||
map for an otherwise equilvalent object.
|
||||
map for an otherwise equivalent object.
|
||||
|
||||
.. change::
|
||||
:tags:
|
||||
@@ -877,7 +877,7 @@
|
||||
:tags:
|
||||
:tickets:
|
||||
|
||||
began to implement newer logic in object properities. you can now say
|
||||
began to implement newer logic in object properties. you can now say
|
||||
myclass.attr.property, which will give you the PropertyLoader corresponding to that
|
||||
attribute, i.e. myclass.mapper.props['attr']
|
||||
|
||||
@@ -943,7 +943,7 @@
|
||||
:tickets:
|
||||
|
||||
fix to engine.process_defaults so it works correctly with a table that has
|
||||
different column name/column keys (changset 982)
|
||||
different column name/column keys (changeset 982)
|
||||
|
||||
.. change::
|
||||
:tags:
|
||||
|
||||
Vendored
+6
-6
@@ -1,7 +1,7 @@
|
||||
|
||||
==============
|
||||
=============
|
||||
0.2 Changelog
|
||||
==============
|
||||
=============
|
||||
|
||||
|
||||
.. changelog::
|
||||
@@ -223,7 +223,7 @@
|
||||
:tags:
|
||||
:tickets:
|
||||
|
||||
modifcation to unitofwork to not maintain ordering within the
|
||||
modification to unitofwork to not maintain ordering within the
|
||||
"new" list or within the UOWTask "objects" list; instead, new objects
|
||||
are tagged with an ordering identifier as they are registered as new
|
||||
with the session, and the INSERT statements are then sorted within the
|
||||
@@ -949,7 +949,7 @@
|
||||
:tags:
|
||||
:tickets:
|
||||
|
||||
fixes to session cascade behavior, entity_name propigation
|
||||
fixes to session cascade behavior, entity_name propagation
|
||||
|
||||
.. change::
|
||||
:tags:
|
||||
@@ -1098,7 +1098,7 @@
|
||||
|
||||
overhaul to Schema to build upon MetaData object instead of an Engine.
|
||||
Entire SQL/Schema system can be used with no Engines whatsoever, executed
|
||||
solely by an explicit Connection object. the "bound" methodlogy exists via the
|
||||
solely by an explicit Connection object. the "bound" methodology exists via the
|
||||
BoundMetaData for schema objects. ProxyEngine is generally not needed
|
||||
anymore and is replaced by DynamicMetaData.
|
||||
|
||||
@@ -1143,7 +1143,7 @@
|
||||
:tickets:
|
||||
|
||||
backrefs create themselves against primary mapper of its originating
|
||||
property, priamry/secondary join arguments can be specified to override.
|
||||
property, primary/secondary join arguments can be specified to override.
|
||||
helps their usage with polymorphic mappers
|
||||
|
||||
.. change::
|
||||
|
||||
Vendored
+11
-11
@@ -1,7 +1,7 @@
|
||||
|
||||
==============
|
||||
=============
|
||||
0.3 Changelog
|
||||
==============
|
||||
=============
|
||||
|
||||
|
||||
.. changelog::
|
||||
@@ -167,7 +167,7 @@
|
||||
:tags: sql
|
||||
:tickets: 667
|
||||
|
||||
foreign key specs can have any chararcter in their identifiers
|
||||
foreign key specs can have any character in their identifiers
|
||||
|
||||
.. change::
|
||||
:tags: sql
|
||||
@@ -878,7 +878,7 @@
|
||||
|
||||
preliminary support for unicode table names, column names and
|
||||
SQL statements added, for databases which can support them.
|
||||
Works with sqlite and postgres so far. Mysql *mostly* works
|
||||
Works with sqlite and postgres so far. MySQL *mostly* works
|
||||
except the has_table() function does not work. Reflection
|
||||
works too.
|
||||
|
||||
@@ -1167,7 +1167,7 @@
|
||||
and the key will be shared. proper positional/named args translate
|
||||
at compile time. for the old behavior of "aliasing" bind parameters
|
||||
with conflicting names, specify "unique=True" - this option is
|
||||
still used internally for all the auto-genererated (value-based)
|
||||
still used internally for all the auto-generated (value-based)
|
||||
bind parameters.
|
||||
|
||||
.. change::
|
||||
@@ -1379,7 +1379,7 @@
|
||||
:tickets:
|
||||
|
||||
some fixes to relationship calcs when using "viewonly=True" to pull
|
||||
in other tables into the join condition which arent parent of the
|
||||
in other tables into the join condition which aren't parent of the
|
||||
relationship's parent/child mappings
|
||||
|
||||
.. change::
|
||||
@@ -1508,7 +1508,7 @@
|
||||
the value of "case_sensitive" defaults to True now, regardless of the
|
||||
casing of the identifier, unless specifically set to False. this is
|
||||
because the object might be label'ed as something else which does
|
||||
contain mixed case, and propigating "case_sensitive=False" breaks that.
|
||||
contain mixed case, and propagating "case_sensitive=False" breaks that.
|
||||
Other fixes to quoting when using labels and "fake" column objects
|
||||
|
||||
.. change::
|
||||
@@ -2622,7 +2622,7 @@
|
||||
index=True/unique=False creates a plain Index,
|
||||
index=True/unique=True on Column creates a unique Index. 'index'
|
||||
and 'unique' keyword arguments to column are now boolean only; for
|
||||
explcit names and groupings of indexes or unique constraints, use the
|
||||
explicit names and groupings of indexes or unique constraints, use the
|
||||
UniqueConstraint/Index constructs explicitly.
|
||||
|
||||
.. change::
|
||||
@@ -2645,7 +2645,7 @@
|
||||
:tickets:
|
||||
|
||||
fixed condition that occurred during reflection when a primary key
|
||||
column was explciitly overridden, where the PrimaryKeyConstraint would
|
||||
column was explicitly overridden, where the PrimaryKeyConstraint would
|
||||
get both the reflected and the programmatic column doubled up
|
||||
|
||||
.. change::
|
||||
@@ -2701,7 +2701,7 @@
|
||||
|
||||
changed "for_update" parameter to accept False/True/"nowait"
|
||||
and "read", the latter two of which are interpreted only by
|
||||
Oracle and Mysql
|
||||
Oracle and MySQL
|
||||
|
||||
.. change::
|
||||
:tags: construction, sql
|
||||
@@ -2753,7 +2753,7 @@
|
||||
:tickets:
|
||||
|
||||
a wide refactoring to "attribute loader" and "options" architectures.
|
||||
ColumnProperty and PropertyLoader define their loading behaivor via switchable
|
||||
ColumnProperty and PropertyLoader define their loading behavior via switchable
|
||||
"strategies", and MapperOptions no longer use mapper/property copying
|
||||
in order to function; they are instead propagated via QueryContext
|
||||
and SelectionContext objects at query/instances time.
|
||||
|
||||
Vendored
+8
-8
@@ -1,7 +1,7 @@
|
||||
|
||||
==============
|
||||
=============
|
||||
0.4 Changelog
|
||||
==============
|
||||
=============
|
||||
|
||||
|
||||
.. changelog::
|
||||
@@ -266,7 +266,7 @@
|
||||
:tickets: 1036
|
||||
|
||||
repaired single table inheritance such that you
|
||||
can single-table inherit from a joined-table inherting
|
||||
can single-table inherit from a joined-table inheriting
|
||||
mapper without issue.
|
||||
|
||||
.. change::
|
||||
@@ -674,7 +674,7 @@
|
||||
whether or not it remains attached to its also-deleted
|
||||
parent.
|
||||
|
||||
- delete-orphan casacde is properly detected on relations
|
||||
- delete-orphan cascade is properly detected on relations
|
||||
that are present on superclasses when using inheritance.
|
||||
|
||||
.. change::
|
||||
@@ -2300,7 +2300,7 @@
|
||||
|
||||
MSSQL
|
||||
- PyODBC no longer has a global "set nocount on".
|
||||
- Fix non-identity integer PKs on autload
|
||||
- Fix non-identity integer PKs on autoload
|
||||
- Better support for convert_unicode
|
||||
- Less strict date conversion for pyodbc/adodbapi
|
||||
- Schema-qualified tables / autoload
|
||||
@@ -2712,7 +2712,7 @@
|
||||
:tickets:
|
||||
|
||||
Renamed the Dialect attribute 'preexecute_sequences' to
|
||||
'preexecute_pk_sequences'. An attribute porxy is in place for
|
||||
'preexecute_pk_sequences'. An attribute proxy is in place for
|
||||
out-of-tree dialects using the old name.
|
||||
|
||||
.. change::
|
||||
@@ -3415,7 +3415,7 @@
|
||||
:tickets:
|
||||
|
||||
Hooks added throughout base/sql/defaults to optimize the calling of bind
|
||||
aram/result processors so that method call overhead is minimized.
|
||||
param/result processors so that method call overhead is minimized.
|
||||
|
||||
.. change::
|
||||
:tags:
|
||||
@@ -4080,7 +4080,7 @@
|
||||
:tags: metadata
|
||||
:tickets:
|
||||
|
||||
Added "explcit" create/drop/execute support for sequences (i.e. you can
|
||||
Added "explicit" create/drop/execute support for sequences (i.e. you can
|
||||
pass a "connectable" to each of those methods on Sequence).
|
||||
|
||||
.. change::
|
||||
|
||||
Vendored
+12
-12
@@ -1,7 +1,7 @@
|
||||
|
||||
==============
|
||||
=============
|
||||
0.5 Changelog
|
||||
==============
|
||||
=============
|
||||
|
||||
|
||||
.. changelog::
|
||||
@@ -599,7 +599,7 @@
|
||||
|
||||
Fixed Query being able to join() from individual columns of a
|
||||
joined-table subclass entity, i.e. query(SubClass.foo,
|
||||
SubcClass.bar).join(<anything>). In most cases, an error
|
||||
SubClass.bar).join(<anything>). In most cases, an error
|
||||
"Could not find a FROM clause to join from" would be
|
||||
raised. In a few others, the result would be returned in terms
|
||||
of the base class rather than the subclass - so applications
|
||||
@@ -783,10 +783,10 @@
|
||||
itself differently to some MapperExtensions.
|
||||
|
||||
The change also affects the internal attribute API, but not
|
||||
the AttributeExtension interface nor any of the publically
|
||||
the AttributeExtension interface nor any of the publicly
|
||||
documented attribute functions.
|
||||
|
||||
- The unit of work no longer genererates a graph of "dependency"
|
||||
- The unit of work no longer generates a graph of "dependency"
|
||||
processors for the full graph of mappers during flush(), instead
|
||||
creating such processors only for those mappers which represent
|
||||
objects with pending changes. This saves a tremendous number
|
||||
@@ -1172,7 +1172,7 @@
|
||||
|
||||
Query won't fail with weakref error when a non-mapper/class
|
||||
instrumented descriptor is passed, raises
|
||||
"Invalid column expession".
|
||||
"Invalid column expression".
|
||||
|
||||
.. change::
|
||||
:tags: orm
|
||||
@@ -1443,7 +1443,7 @@
|
||||
:tickets: 1237, 781
|
||||
|
||||
Added a new `relation()` keyword `back_populates`. This
|
||||
allows configuation of backreferences using explicit
|
||||
allows configuration of backreferences using explicit
|
||||
relations. This is required when creating
|
||||
bidirectional relations between a hierarchy of concrete
|
||||
mappers and another class.
|
||||
@@ -1461,7 +1461,7 @@
|
||||
|
||||
Query.from_self() as well as query.subquery() both disable
|
||||
the rendering of eager joins inside the subquery produced.
|
||||
The "disable all eager joins" feature is available publically
|
||||
The "disable all eager joins" feature is available publicly
|
||||
via a new query.enable_eagerloads() generative.
|
||||
|
||||
.. change::
|
||||
@@ -1470,7 +1470,7 @@
|
||||
|
||||
Added a rudimental series of set operations to Query that
|
||||
receive Query objects as arguments, including union(),
|
||||
union_all(), intersect(), except_(), insertsect_all(),
|
||||
union_all(), intersect(), except_(), intersect_all(),
|
||||
except_all(). See the API documentation for
|
||||
Query.union() for examples.
|
||||
|
||||
@@ -1525,7 +1525,7 @@
|
||||
Using delete-orphan on a many-to-many relation is deprecated.
|
||||
This produces misleading or erroneous results since SQLA does
|
||||
not retrieve the full list of "parents" for m2m. To get delete-orphan
|
||||
behavior with an m2m table, use an explcit association class
|
||||
behavior with an m2m table, use an explicit association class
|
||||
so that the individual association row is treated as a parent.
|
||||
|
||||
.. change::
|
||||
@@ -2651,7 +2651,7 @@
|
||||
Added more granularity to internal attribute access, such that
|
||||
cascade and flush operations will not initialize unloaded
|
||||
attributes and collections, leaving them intact for a
|
||||
lazy-load later on. Backref events still initialize attrbutes
|
||||
lazy-load later on. Backref events still initialize attributes
|
||||
and collections for pending instances.
|
||||
|
||||
.. change::
|
||||
@@ -3461,7 +3461,7 @@
|
||||
:tickets:
|
||||
|
||||
Fixed query.join() when used in conjunction with a
|
||||
columns-only clause and an SQL-expression ON clause in the
|
||||
columns-only clause and a SQL-expression ON clause in the
|
||||
join.
|
||||
|
||||
.. change::
|
||||
|
||||
Vendored
+20
-20
@@ -1,7 +1,7 @@
|
||||
|
||||
==============
|
||||
=============
|
||||
0.6 Changelog
|
||||
==============
|
||||
=============
|
||||
|
||||
|
||||
.. changelog::
|
||||
@@ -524,7 +524,7 @@
|
||||
cleanup() were not explicitly closed, leaving garbage
|
||||
collection to the task instead. This generally only
|
||||
affects non-reference-counting backends like Jython
|
||||
and Pypy. Thanks to Jaimy Azle for spotting
|
||||
and PyPy. Thanks to Jaimy Azle for spotting
|
||||
this.
|
||||
|
||||
.. change::
|
||||
@@ -543,7 +543,7 @@
|
||||
of the auto-generated sequence of a SERIAL column,
|
||||
which currently only occurs if implicit_returning=False,
|
||||
now accommodates if the table + column name is greater
|
||||
than 63 characters using the same logic Postgresql uses.
|
||||
than 63 characters using the same logic PostgreSQL uses.
|
||||
|
||||
.. change::
|
||||
:tags: postgresql
|
||||
@@ -1309,7 +1309,7 @@
|
||||
@classproperty 's official name/location for usage
|
||||
with declarative is sqlalchemy.ext.declarative.declared_attr.
|
||||
Same thing, but moving there since it is more of a
|
||||
"marker" that's specific to declararative,
|
||||
"marker" that's specific to declarative,
|
||||
not just an attribute technique.
|
||||
|
||||
.. change::
|
||||
@@ -1390,7 +1390,7 @@
|
||||
:tags: oracle
|
||||
:tickets: 1878
|
||||
|
||||
The implicit_retunring argument to create_engine()
|
||||
The implicit_returning argument to create_engine()
|
||||
is now honored regardless of detected version of
|
||||
Oracle. Previously, the flag would be forced
|
||||
to False if server version info was < 10.
|
||||
@@ -1465,7 +1465,7 @@
|
||||
changed to StaleDataError, and descriptive
|
||||
error messages have been revised to reflect
|
||||
exactly what the issue is. Both names will
|
||||
remain available for the forseeable future
|
||||
remain available for the foreseeable future
|
||||
for schemes that may be specifying
|
||||
ConcurrentModificationError in an "except:"
|
||||
clause.
|
||||
@@ -1477,7 +1477,7 @@
|
||||
Added a mutex to the identity map which mutexes
|
||||
remove operations against iteration methods,
|
||||
which now pre-buffer before returning an
|
||||
iterable. This because asyncrhonous gc
|
||||
iterable. This because asynchronous gc
|
||||
can remove items via the gc thread at any time.
|
||||
|
||||
.. change::
|
||||
@@ -2479,7 +2479,7 @@
|
||||
:tags: sql
|
||||
:tickets: 1571
|
||||
|
||||
Fixed "table" argument on constructor of ForeginKeyConstraint
|
||||
Fixed "table" argument on constructor of ForeignKeyConstraint
|
||||
|
||||
.. change::
|
||||
:tags: sql
|
||||
@@ -2850,7 +2850,7 @@
|
||||
:tags: postgresql
|
||||
:tickets: 1071
|
||||
|
||||
Postgresql now reflects sequence names associated with
|
||||
PostgreSQL now reflects sequence names associated with
|
||||
SERIAL columns correctly, after the name of the sequence
|
||||
has been changed. Thanks to Kumar McMillan for the patch.
|
||||
|
||||
@@ -2873,7 +2873,7 @@
|
||||
:tags: postgresql
|
||||
:tickets: 1769
|
||||
|
||||
Postgresql reflects the name of primary key constraints,
|
||||
PostgreSQL reflects the name of primary key constraints,
|
||||
if one exists.
|
||||
|
||||
.. change::
|
||||
@@ -3462,7 +3462,7 @@
|
||||
as well as the adaptation of the Python operator into
|
||||
a SQL operator, based on the full left/right/operator
|
||||
of the given expression. In particular
|
||||
the date/time/interval system created for Postgresql
|
||||
the date/time/interval system created for PostgreSQL
|
||||
EXTRACT in has now been generalized into
|
||||
the type system. The previous behavior which often
|
||||
occurred of an expression "column + literal" forcing
|
||||
@@ -3845,7 +3845,7 @@
|
||||
:tickets:
|
||||
|
||||
For the full set of feature descriptions, see
|
||||
http://www.sqlalchemy.org/trac/wiki/06Migration .
|
||||
http://docs.sqlalchemy.org/en/latest/changelog/migration_06.html .
|
||||
This document is a work in progress.
|
||||
|
||||
.. change::
|
||||
@@ -4259,7 +4259,7 @@
|
||||
|
||||
returning() support is native to insert(), update(),
|
||||
delete(). Implementations of varying levels of
|
||||
functionality exist for Postgresql, Firebird, MSSQL and
|
||||
functionality exist for PostgreSQL, Firebird, MSSQL and
|
||||
Oracle. returning() can be called explicitly with column
|
||||
expressions which are then returned in the resultset,
|
||||
usually via fetchone() or first().
|
||||
@@ -4280,7 +4280,7 @@
|
||||
another will now be grouped with parenthesis - previously,
|
||||
the first compound element in the list would not be grouped,
|
||||
as SQLite doesn't like a statement to start with
|
||||
parenthesis. However, Postgresql in particular has
|
||||
parenthesis. However, PostgreSQL in particular has
|
||||
precedence rules regarding INTERSECT, and it is
|
||||
more consistent for parenthesis to be applied equally
|
||||
to all sub-elements. So now, the workaround for SQLite
|
||||
@@ -4586,7 +4586,7 @@
|
||||
|
||||
The "start" and "increment" attributes on Sequence now
|
||||
generate "START WITH" and "INCREMENT BY" by default,
|
||||
on Oracle and Postgresql. Firebird doesn't support
|
||||
on Oracle and PostgreSQL. Firebird doesn't support
|
||||
these keywords right now.
|
||||
|
||||
.. change::
|
||||
@@ -5227,7 +5227,7 @@
|
||||
:tickets:
|
||||
|
||||
The construction of types within dialects has been totally
|
||||
overhauled. Dialects now define publically available types
|
||||
overhauled. Dialects now define publicly available types
|
||||
as UPPERCASE names exclusively, and internal implementation
|
||||
types using underscore identifiers (i.e. are private).
|
||||
The system by which types are expressed in SQL and DDL
|
||||
@@ -5279,7 +5279,7 @@
|
||||
optimized, resulting in varying speed improvements:
|
||||
Unicode, PickleType, Interval, TypeDecorator, Binary.
|
||||
Also the following dbapi-specific implementations have been improved:
|
||||
Time, Date and DateTime on Sqlite, ARRAY on Postgresql,
|
||||
Time, Date and DateTime on Sqlite, ARRAY on PostgreSQL,
|
||||
Time on MySQL, Numeric(as_decimal=False) on MySQL, oursql and
|
||||
pypostgresql, DateTime on cx_oracle and LOB-based types on cx_oracle.
|
||||
|
||||
@@ -5332,7 +5332,7 @@
|
||||
|
||||
PickleType now uses == for comparison of values when
|
||||
mutable=True, unless the "comparator" argument with a
|
||||
comparsion function is specified to the type. Objects
|
||||
comparison function is specified to the type. Objects
|
||||
being pickled will be compared based on identity (which
|
||||
defeats the purpose of mutable=True) if __eq__() is not
|
||||
overridden or a comparison function is not provided.
|
||||
@@ -5368,7 +5368,7 @@
|
||||
session, using autocommit=False, autoflush=True. Default
|
||||
behavior of SQLSoup now requires the usual usage of commit()
|
||||
and rollback(), which have been added to its interface. An
|
||||
explcit Session or scoped_session can be passed to the
|
||||
explicit Session or scoped_session can be passed to the
|
||||
constructor, allowing these arguments to be overridden.
|
||||
|
||||
.. change::
|
||||
|
||||
Vendored
+17
-17
@@ -1,7 +1,7 @@
|
||||
|
||||
==============
|
||||
=============
|
||||
0.7 Changelog
|
||||
==============
|
||||
=============
|
||||
|
||||
.. changelog::
|
||||
:version: 0.7.11
|
||||
@@ -88,7 +88,7 @@
|
||||
:tickets: 2676
|
||||
:versions: 0.8.0
|
||||
|
||||
Added support for Postgresql's traditional SUBSTRING
|
||||
Added support for PostgreSQL's traditional SUBSTRING
|
||||
function syntax, renders as "SUBSTRING(x FROM y FOR z)"
|
||||
when regular ``func.substring()`` is used.
|
||||
Courtesy Gunnlaugur Þór Briem.
|
||||
@@ -586,7 +586,7 @@
|
||||
|
||||
Fixed compiler bug whereby using a correlated
|
||||
subquery within an ORDER BY would fail to render correctly
|
||||
if the stament also used LIMIT/OFFSET, due to mis-rendering
|
||||
if the statement also used LIMIT/OFFSET, due to mis-rendering
|
||||
within the ROW_NUMBER() OVER clause. Fix courtesy
|
||||
sayap
|
||||
|
||||
@@ -885,7 +885,7 @@
|
||||
:tickets: 2445
|
||||
|
||||
Added new for_update/with_lockmode()
|
||||
options for Postgresql: for_update="read"/
|
||||
options for PostgreSQL: for_update="read"/
|
||||
with_lockmode("read"),
|
||||
for_update="read_nowait"/
|
||||
with_lockmode("read_nowait").
|
||||
@@ -1873,7 +1873,7 @@
|
||||
The update() construct can now accommodate
|
||||
multiple tables in the WHERE clause, which will
|
||||
render an "UPDATE..FROM" construct, recognized by
|
||||
Postgresql and MSSQL. When compiled on MySQL,
|
||||
PostgreSQL and MSSQL. When compiled on MySQL,
|
||||
will instead generate "UPDATE t1, t2, ..". MySQL
|
||||
additionally can render against multiple tables in the
|
||||
SET clause, if Column objects are used as keys
|
||||
@@ -1968,7 +1968,7 @@
|
||||
:tickets: 1679
|
||||
|
||||
a "has_schema" method has been implemented
|
||||
on dialect, but only works on Postgresql so far.
|
||||
on dialect, but only works on PostgreSQL so far.
|
||||
Courtesy Manlio Perillo.
|
||||
|
||||
.. change::
|
||||
@@ -2025,7 +2025,7 @@
|
||||
:tags: postgresql, bug
|
||||
:tickets: 2311
|
||||
|
||||
Postgresql dialect memoizes that an ENUM of a
|
||||
PostgreSQL dialect memoizes that an ENUM of a
|
||||
particular name was processed
|
||||
during a create/drop sequence. This allows
|
||||
a create/drop sequence to work without any
|
||||
@@ -3220,7 +3220,7 @@
|
||||
This section documents those changes from 0.7b4
|
||||
to 0.7.0. For an overview of what's new in
|
||||
SQLAlchemy 0.7, see
|
||||
http://www.sqlalchemy.org/trac/wiki/07Migration
|
||||
http://docs.sqlalchemy.org/en/latest/changelog/migration_07.html
|
||||
|
||||
.. change::
|
||||
:tags: orm
|
||||
@@ -3696,7 +3696,7 @@
|
||||
:tickets: 2081
|
||||
|
||||
REAL has been added to the core types. Supported
|
||||
by Postgresql, SQL Server, MySQL, SQLite. Note
|
||||
by PostgreSQL, SQL Server, MySQL, SQLite. Note
|
||||
that the SQL Server and MySQL versions, which
|
||||
add extra arguments, are also still available
|
||||
from those dialects.
|
||||
@@ -3790,7 +3790,7 @@
|
||||
:tags: general
|
||||
:tickets:
|
||||
|
||||
Lots of fixes to unit tests when run under Pypy
|
||||
Lots of fixes to unit tests when run under PyPy
|
||||
(courtesy Alex Gaynor).
|
||||
|
||||
.. change::
|
||||
@@ -4125,7 +4125,7 @@
|
||||
|
||||
Detailed descriptions of each change below are
|
||||
described at:
|
||||
http://www.sqlalchemy.org/trac/wiki/07Migration
|
||||
http://docs.sqlalchemy.org/en/latest/changelog/migration_07.html
|
||||
|
||||
.. change::
|
||||
:tags: general
|
||||
@@ -4348,7 +4348,7 @@
|
||||
:tickets: 1069
|
||||
|
||||
Query.distinct() now accepts column expressions
|
||||
as \*args, interpreted by the Postgresql dialect
|
||||
as \*args, interpreted by the PostgreSQL dialect
|
||||
as DISTINCT ON (<expr>).
|
||||
|
||||
.. change::
|
||||
@@ -4448,7 +4448,7 @@
|
||||
:tickets: 1069
|
||||
|
||||
select.distinct() now accepts column expressions
|
||||
as \*args, interpreted by the Postgresql dialect
|
||||
as \*args, interpreted by the PostgreSQL dialect
|
||||
as DISTINCT ON (<expr>). Note this was already
|
||||
available via passing a list to the `distinct`
|
||||
keyword argument to select().
|
||||
@@ -4531,7 +4531,7 @@
|
||||
"isolation_level" argument, sets transaction isolation
|
||||
level for that connection only until returned to the
|
||||
connection pool, for those backends which support it
|
||||
(SQLite, Postgresql)
|
||||
(SQLite, PostgreSQL)
|
||||
|
||||
.. change::
|
||||
:tags: sql
|
||||
@@ -4648,7 +4648,7 @@
|
||||
of the auto-generated sequence of a SERIAL column,
|
||||
which currently only occurs if implicit_returning=False,
|
||||
now accommodates if the table + column name is greater
|
||||
than 63 characters using the same logic Postgresql uses. (also in 0.6.7)
|
||||
than 63 characters using the same logic PostgreSQL uses. (also in 0.6.7)
|
||||
|
||||
.. change::
|
||||
:tags: postgresql
|
||||
@@ -4668,7 +4668,7 @@
|
||||
'unbounded'. This also occurs for the VARBINARY type..
|
||||
|
||||
This behavior makes these types more closely compatible
|
||||
with Postgresql's VARCHAR type which is similarly unbounded
|
||||
with PostgreSQL's VARCHAR type which is similarly unbounded
|
||||
when no length is specified.
|
||||
|
||||
.. change::
|
||||
|
||||
Vendored
+31
-43
@@ -1,7 +1,7 @@
|
||||
|
||||
==============
|
||||
=============
|
||||
0.8 Changelog
|
||||
==============
|
||||
=============
|
||||
|
||||
.. changelog_imports::
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
:tickets: 3044
|
||||
|
||||
Fixed bug in INSERT..FROM SELECT construct where selecting from a
|
||||
UNION would wrap the union in an anonymous (e.g. unlabled) subquery.
|
||||
UNION would wrap the union in an anonymous (e.g. unlabeled) subquery.
|
||||
|
||||
.. change::
|
||||
:tags: bug, postgresql
|
||||
@@ -127,7 +127,6 @@
|
||||
.. change::
|
||||
:tags: bug, ext
|
||||
:versions: 0.9.5, 1.0.0b1
|
||||
:pullreq: bitbucket:24
|
||||
:tickets: 3093, 3051
|
||||
|
||||
Fixed bug where :meth:`.MutableDict.setdefault` didn't return the
|
||||
@@ -137,7 +136,6 @@
|
||||
.. change::
|
||||
:tags: bug, mysql
|
||||
:versions: 0.9.5, 1.0.0b1
|
||||
:pullreq: bitbucket:15
|
||||
|
||||
Added support for reflecting tables where an index includes
|
||||
KEY_BLOCK_SIZE using an equal sign. Pull request courtesy
|
||||
@@ -165,7 +163,6 @@
|
||||
|
||||
.. change::
|
||||
:tags: bug, postgresql
|
||||
:pullreq: bitbucket:13
|
||||
:versions: 0.9.5, 1.0.0b1
|
||||
|
||||
Added a new "disconnect" message "connection has been closed unexpectedly".
|
||||
@@ -197,7 +194,7 @@
|
||||
:versions: 0.9.4
|
||||
|
||||
Fixed regression caused by release 0.8.5 / 0.9.3's compatibility
|
||||
enhancements where index reflection on Postgresql versions specific
|
||||
enhancements where index reflection on PostgreSQL versions specific
|
||||
to only the 8.1, 8.2 series again
|
||||
broke, surrounding the ever problematic int2vector type. While
|
||||
int2vector supports array operations as of 8.1, apparently it only
|
||||
@@ -252,7 +249,7 @@
|
||||
Fixed bug in :func:`.tuple_` construct where the "type" of essentially
|
||||
the first SQL expression would be applied as the "comparison type"
|
||||
to a compared tuple value; this has the effect in some cases of an
|
||||
inappropriate "type coersion" occurring, such as when a tuple that
|
||||
inappropriate "type coercion" occurring, such as when a tuple that
|
||||
has a mix of String and Binary values improperly coerces target
|
||||
values to Binary even though that's not what they are on the left
|
||||
side. :func:`.tuple_` now expects heterogeneous types within its
|
||||
@@ -284,8 +281,8 @@
|
||||
:tags: postgresql, bug
|
||||
:versions: 0.9.3
|
||||
|
||||
Support has been improved for Postgresql reflection behavior on very old
|
||||
(pre 8.1) versions of Postgresql, and potentially other PG engines
|
||||
Support has been improved for PostgreSQL reflection behavior on very old
|
||||
(pre 8.1) versions of PostgreSQL, and potentially other PG engines
|
||||
such as Redshift (assuming Redshift reports the version as < 8.1).
|
||||
The query for "indexes" as well as "primary keys" relies upon inspecting
|
||||
a so-called "int2vector" datatype, which refuses to coerce to an array
|
||||
@@ -311,7 +308,6 @@
|
||||
:tags: bug, mysql
|
||||
:versions: 0.9.3
|
||||
:tickets: 2966
|
||||
:pullreq: bitbucket:12
|
||||
|
||||
Added support for the ``PARTITION BY`` and ``PARTITIONS``
|
||||
MySQL table keywords, specified as ``mysql_partition_by='value'`` and
|
||||
@@ -339,7 +335,6 @@
|
||||
|
||||
.. change::
|
||||
:tags: bug, sqlite
|
||||
:pullreq: github:72
|
||||
|
||||
Restored a change that was missed in the backport of unique
|
||||
constraint reflection to 0.8, where :class:`.UniqueConstraint`
|
||||
@@ -351,10 +346,10 @@
|
||||
:tickets: 2291
|
||||
:versions: 0.9.3
|
||||
|
||||
Revised this very old issue where the Postgresql "get primary key"
|
||||
Revised this very old issue where the PostgreSQL "get primary key"
|
||||
reflection query were updated to take into account primary key constraints
|
||||
that were renamed; the newer query fails on very old versions of
|
||||
Postgresql such as version 7, so the old query is restored in those cases
|
||||
PostgreSQL such as version 7, so the old query is restored in those cases
|
||||
when server_version_info < (8, 0) is detected.
|
||||
|
||||
.. change::
|
||||
@@ -392,7 +387,6 @@
|
||||
|
||||
.. change::
|
||||
:tags: bug, mysql
|
||||
:pullreq: github:61
|
||||
:versions: 0.9.2
|
||||
|
||||
Some missing methods added to the cymysql dialect, including
|
||||
@@ -401,7 +395,6 @@
|
||||
|
||||
.. change::
|
||||
:tags: bug, py3k
|
||||
:pullreq: github:63
|
||||
|
||||
Fixed Py3K bug where a missing import would cause "literal binary"
|
||||
mode to fail to import "util.binary_type" when rendering a bound
|
||||
@@ -411,7 +404,6 @@
|
||||
.. change::
|
||||
:tags: bug, orm
|
||||
:versions: 0.9.2
|
||||
:pullreq: github:58
|
||||
|
||||
Fixed error message when an iterator object is passed to
|
||||
:func:`.class_mapper` or similar, where the error would fail to
|
||||
@@ -444,7 +436,6 @@
|
||||
.. change::
|
||||
:tags: bug, mssql, pymssql
|
||||
:versions: 0.9.0
|
||||
:pullreq: github:51
|
||||
|
||||
Added "Net-Lib error during Connection reset by peer" message
|
||||
to the list of messages checked for "disconnect" within the
|
||||
@@ -571,7 +562,6 @@
|
||||
.. change::
|
||||
:tags: bug, mssql
|
||||
:versions: 0.9.0
|
||||
:pullreq: bitbucket:7
|
||||
|
||||
Fixed bug introduced in 0.8.0 where the ``DROP INDEX``
|
||||
statement for an index in MSSQL would render incorrectly if the
|
||||
@@ -798,8 +788,8 @@
|
||||
:tickets: 2819
|
||||
:versions: 0.9.0b1
|
||||
|
||||
Fixed bug where Postgresql version strings that had a prefix preceding
|
||||
the words "Postgresql" or "EnterpriseDB" would not parse.
|
||||
Fixed bug where PostgreSQL version strings that had a prefix preceding
|
||||
the words "PostgreSQL" or "EnterpriseDB" would not parse.
|
||||
Courtesy Scott Schaefer.
|
||||
|
||||
.. change::
|
||||
@@ -834,10 +824,10 @@
|
||||
|
||||
Added a new flag ``system=True`` to :class:`.Column`, which marks
|
||||
the column as a "system" column which is automatically made present
|
||||
by the database (such as Postgresql ``oid`` or ``xmin``). The
|
||||
by the database (such as PostgreSQL ``oid`` or ``xmin``). The
|
||||
column will be omitted from the ``CREATE TABLE`` statement but will
|
||||
otherwise be available for querying. In addition, the
|
||||
:class:`.CreateColumn` construct can be appled to a custom
|
||||
:class:`.CreateColumn` construct can be applied to a custom
|
||||
compilation rule which allows skipping of columns, by producing
|
||||
a rule that returns ``None``.
|
||||
|
||||
@@ -858,7 +848,7 @@
|
||||
|
||||
Fixed a potential issue in an ordered sequence implementation used
|
||||
by the ORM to iterate mapper hierarchies; under the Jython interpreter
|
||||
this implementation wasn't ordered, even though cPython and Pypy
|
||||
this implementation wasn't ordered, even though cPython and PyPy
|
||||
maintained ordering.
|
||||
|
||||
.. change::
|
||||
@@ -942,7 +932,7 @@
|
||||
form of a some expressions when referring to the ``.c`` collection
|
||||
on a ``select()`` construct, but the ``str()`` form isn't available
|
||||
since the element relies on dialect-specific compilation constructs,
|
||||
notably the ``__getitem__()`` operator as used with a Postgresql
|
||||
notably the ``__getitem__()`` operator as used with a PostgreSQL
|
||||
``ARRAY`` element. The fix also adds a new exception class
|
||||
:exc:`.UnsupportedCompilationError` which is raised in those cases
|
||||
where a compiler is asked to compile something it doesn't know
|
||||
@@ -1069,7 +1059,7 @@
|
||||
:versions: 0.9.0b1
|
||||
|
||||
The behavior of :func:`.extract` has been simplified on the
|
||||
Postgresql dialect to no longer inject a hardcoded ``::timestamp``
|
||||
PostgreSQL dialect to no longer inject a hardcoded ``::timestamp``
|
||||
or similar cast into the given expression, as this interfered
|
||||
with types such as timezone-aware datetimes, but also
|
||||
does not appear to be at all necessary with modern versions
|
||||
@@ -1103,7 +1093,7 @@
|
||||
:versions: 0.9.0b1
|
||||
|
||||
Fixed bug where the order of columns in a multi-column
|
||||
Postgresql index would be reflected in the wrong order.
|
||||
PostgreSQL index would be reflected in the wrong order.
|
||||
Courtesy Roman Podolyaka.
|
||||
|
||||
.. change::
|
||||
@@ -1167,7 +1157,7 @@
|
||||
:tags: feature, postgresql
|
||||
:versions: 0.9.0b1
|
||||
|
||||
Support for Postgresql 9.2 range types has been added.
|
||||
Support for PostgreSQL 9.2 range types has been added.
|
||||
Currently, no type translation is provided, so works
|
||||
directly with strings or psycopg2 2.5 range extension types
|
||||
at the moment. Patch courtesy Chris Withers.
|
||||
@@ -1202,7 +1192,6 @@
|
||||
|
||||
.. change::
|
||||
:tags: bug, engine
|
||||
:pullreq: github:6
|
||||
:versions: 0.9.0b1
|
||||
|
||||
Fixed bug where the ``reset_on_return`` argument to various :class:`.Pool`
|
||||
@@ -1334,7 +1323,6 @@
|
||||
|
||||
.. change::
|
||||
:tags: bug, postgresql
|
||||
:pullreq: github:2
|
||||
:tickets: 2735
|
||||
|
||||
Fixed the HSTORE type to correctly encode/decode for unicode.
|
||||
@@ -1463,7 +1451,7 @@
|
||||
:tags: bug, postgresql
|
||||
:tickets: 2681
|
||||
|
||||
The operators for the Postgresql ARRAY type supports
|
||||
The operators for the PostgreSQL ARRAY type supports
|
||||
input types of sets, generators, etc. even when
|
||||
a dimension is not specified, by turning the given
|
||||
iterable into a collection unconditionally.
|
||||
@@ -1872,7 +1860,7 @@
|
||||
is now copied in all cases when :meth:`.Table.tometadata` happens,
|
||||
and if ``inherit_schema=True``, the type will take on the new
|
||||
schema name passed to the method. The ``schema`` is important
|
||||
when used with the Postgresql backend, as the type results in
|
||||
when used with the PostgreSQL backend, as the type results in
|
||||
a ``CREATE TYPE`` statement.
|
||||
|
||||
.. change::
|
||||
@@ -1945,7 +1933,7 @@
|
||||
custom collections using an ``__instrumentation__`` datastructure
|
||||
associated with the collection has been removed, as this was a complex
|
||||
and untested feature which was also essentially redundant versus the
|
||||
decorator approach. Other internal simplifcations to the
|
||||
decorator approach. Other internal simplifications to the
|
||||
orm.collections module have been made as well.
|
||||
|
||||
.. change::
|
||||
@@ -2153,7 +2141,7 @@
|
||||
The :class:`.Insert` construct now supports multi-valued inserts,
|
||||
that is, an INSERT that renders like
|
||||
"INSERT INTO table VALUES (...), (...), ...".
|
||||
Supported by Postgresql, SQLite, and MySQL.
|
||||
Supported by PostgreSQL, SQLite, and MySQL.
|
||||
Big thanks to Idan Kamara for doing the legwork on this one.
|
||||
|
||||
.. seealso::
|
||||
@@ -2272,7 +2260,7 @@
|
||||
:tags: postgresql, feature
|
||||
:tickets: 2606
|
||||
|
||||
:class:`.HSTORE` is now available in the Postgresql dialect.
|
||||
:class:`.HSTORE` is now available in the PostgreSQL dialect.
|
||||
Will also use psycopg2's extensions if available. Courtesy
|
||||
Audrius Kažukauskas.
|
||||
|
||||
@@ -2440,7 +2428,7 @@
|
||||
:tickets: 2589
|
||||
|
||||
The Beaker caching example has been converted
|
||||
to use `dogpile.cache <http://dogpilecache.readthedocs.org/>`_.
|
||||
to use `dogpile.cache <https://dogpilecache.readthedocs.io/>`_.
|
||||
This is a new caching library written by the same
|
||||
creator of Beaker's caching internals, and represents a
|
||||
vastly improved, simplified, and modernized system of caching.
|
||||
@@ -2677,7 +2665,7 @@
|
||||
UPDATE..FROM syntax as allowed by the dialect
|
||||
to satisfy the WHERE clause. MySQL's multi-table
|
||||
update feature is also supported if columns
|
||||
are specified by object in the "values" dicitionary.
|
||||
are specified by object in the "values" dictionary.
|
||||
PG's DELETE..USING is also not available
|
||||
in Core yet.
|
||||
|
||||
@@ -3189,17 +3177,17 @@
|
||||
to augment bind- and result- behavior at the
|
||||
SQL level, as opposed to in the Python level.
|
||||
Allows for schemes like transparent encryption/
|
||||
decryption, usage of Postgis functions, etc.
|
||||
decryption, usage of PostGIS functions, etc.
|
||||
|
||||
.. change::
|
||||
:tags: feature, sql
|
||||
:tickets:
|
||||
|
||||
The Core oeprator system now includes
|
||||
The Core operator system now includes
|
||||
the `getitem` operator, i.e. the bracket
|
||||
operator in Python. This is used at first
|
||||
to provide index and slice behavior to the
|
||||
Postgresql ARRAY type, and also provides a hook
|
||||
PostgreSQL ARRAY type, and also provides a hook
|
||||
for end-user definition of custom __getitem__
|
||||
schemes which can be applied at the type
|
||||
level as well as within ORM-level custom
|
||||
@@ -3237,7 +3225,7 @@
|
||||
String types. When present, renders as
|
||||
COLLATE <collation>. This to support the
|
||||
COLLATE keyword now supported by several
|
||||
databases including MySQL, SQLite, and Postgresql.
|
||||
databases including MySQL, SQLite, and PostgreSQL.
|
||||
|
||||
.. change::
|
||||
:tags: change, sql
|
||||
@@ -3603,7 +3591,7 @@
|
||||
:tags: postgresql, feature
|
||||
:tickets: 2506
|
||||
|
||||
Added support for the Postgresql ONLY
|
||||
Added support for the PostgreSQL ONLY
|
||||
keyword, which can appear corresponding to a
|
||||
table in a SELECT, UPDATE, or DELETE statement.
|
||||
The phrase is established using with_hint().
|
||||
@@ -3614,7 +3602,7 @@
|
||||
:tickets:
|
||||
|
||||
The "ischema_names" dictionary of the
|
||||
Postgresql dialect is "unofficially" customizable.
|
||||
PostgreSQL dialect is "unofficially" customizable.
|
||||
Meaning, new types such as PostGIS types can
|
||||
be added into this dictionary, and the PG type
|
||||
reflection code should be able to handle simple
|
||||
|
||||
Vendored
+47
-75
@@ -1,7 +1,6 @@
|
||||
|
||||
==============
|
||||
=============
|
||||
0.9 Changelog
|
||||
==============
|
||||
=============
|
||||
|
||||
.. changelog_imports::
|
||||
|
||||
@@ -11,9 +10,20 @@
|
||||
.. include:: changelog_07.rst
|
||||
:start-line: 5
|
||||
|
||||
.. changelog::
|
||||
.. _unreleased_changelog::
|
||||
:version: 0.9.11
|
||||
|
||||
.. change::
|
||||
:tags: bug, oracle, py3k
|
||||
:tickets: 3491
|
||||
:versions: 1.0.9
|
||||
|
||||
Fixed support for cx_Oracle version 5.2, which was tripping
|
||||
up SQLAlchemy's version detection under Python 3 and inadvertently
|
||||
not using the correct unicode mode for Python 3. This would cause
|
||||
issues such as bound variables mis-interpreted as NULL and rows
|
||||
silently not being returned.
|
||||
|
||||
.. change::
|
||||
:tags: bug, engine
|
||||
:tickets: 3497
|
||||
@@ -145,7 +155,6 @@
|
||||
.. change::
|
||||
:tags: bug, py3k, mysql
|
||||
:tickets: 3333
|
||||
:pullreq: github:158
|
||||
:versions: 1.0.0b2
|
||||
|
||||
Fixed the :class:`.mysql.BIT` type on Py3K which was not using the
|
||||
@@ -180,10 +189,9 @@
|
||||
|
||||
.. change::
|
||||
:tags: feature, postgresql
|
||||
:pullreq: bitbucket:45
|
||||
:versions: 1.0.0b1
|
||||
|
||||
Added support for the ``CONCURRENTLY`` keyword with Postgresql
|
||||
Added support for the ``CONCURRENTLY`` keyword with PostgreSQL
|
||||
indexes, established using ``postgresql_concurrently``. Pull
|
||||
request courtesy Iuri de Silvio.
|
||||
|
||||
@@ -193,7 +201,6 @@
|
||||
|
||||
.. change::
|
||||
:tags: bug, ext, py3k
|
||||
:pullreq: github:154
|
||||
:versions: 1.0.0b1
|
||||
|
||||
Fixed bug where the association proxy list class would not interpret
|
||||
@@ -202,7 +209,6 @@
|
||||
|
||||
.. change::
|
||||
:tags: feature, sqlite
|
||||
:pullreq: bitbucket:42
|
||||
:versions: 1.0.0b1
|
||||
|
||||
Added support for partial indexes (e.g. with a WHERE clause) on
|
||||
@@ -238,7 +244,6 @@
|
||||
|
||||
.. change::
|
||||
:tags: bug, orm
|
||||
:pullreq: github:147
|
||||
:versions: 1.0.0b1
|
||||
|
||||
Fixed bug where TypeError raised when :meth:`.Query.join` called
|
||||
@@ -301,7 +306,7 @@
|
||||
:tickets: 2940
|
||||
:versions: 1.0.0b1
|
||||
|
||||
Repaired support for Postgresql UUID types in conjunction with
|
||||
Repaired support for PostgreSQL UUID types in conjunction with
|
||||
the ARRAY type when using psycopg2. The psycopg2 dialect now
|
||||
employs use of the psycopg2.extras.register_uuid() hook
|
||||
so that UUID values are always passed to/from the DBAPI as
|
||||
@@ -311,7 +316,6 @@
|
||||
|
||||
.. change::
|
||||
:tags: bug, postgresql
|
||||
:pullreq: github:145
|
||||
:versions: 1.0.0b1
|
||||
|
||||
Added support for the :class:`postgresql.JSONB` datatype when
|
||||
@@ -320,7 +324,7 @@
|
||||
additionally, the newly added psycopg2 extension
|
||||
``extras.register_default_jsonb`` is used to establish a JSON
|
||||
deserializer passed to the dialect via the ``json_deserializer``
|
||||
argument. Also repaired the Postgresql integration tests which
|
||||
argument. Also repaired the PostgreSQL integration tests which
|
||||
weren't actually round-tripping the JSONB type as opposed to the
|
||||
JSON type. Pull request courtesy Mateusz Susik.
|
||||
|
||||
@@ -363,7 +367,7 @@
|
||||
:versions: 1.0.0b1
|
||||
:tickets: 3174
|
||||
|
||||
Fixed bug where Postgresql dialect would fail to render an
|
||||
Fixed bug where PostgreSQL dialect would fail to render an
|
||||
expression in an :class:`.Index` that did not correspond directly
|
||||
to a table-bound column; typically when a :func:`.text` construct
|
||||
was one of the expressions within the index; or could misinterpret the
|
||||
@@ -387,7 +391,6 @@
|
||||
.. change::
|
||||
:tags: bug, sql
|
||||
:versions: 1.0.0b1
|
||||
:pullreq: bitbucket:41
|
||||
|
||||
Added the ``native_enum`` flag to the ``__repr__()`` output
|
||||
of :class:`.Enum`, which is mostly important when using it with
|
||||
@@ -402,7 +405,7 @@
|
||||
:class:`.Query` before it fetched results, particularly when
|
||||
row processors can't be formed, the cursor would stay open with
|
||||
results pending and not actually be closed. This is typically only
|
||||
an issue on an interpreter like Pypy where the cursor isn't
|
||||
an issue on an interpreter like PyPy where the cursor isn't
|
||||
immediately GC'ed, and can in some circumstances lead to transactions/
|
||||
locks being open longer than is desirable.
|
||||
|
||||
@@ -463,7 +466,7 @@
|
||||
:tags: bug, examples
|
||||
:versions: 1.0.0b1
|
||||
|
||||
Fixed a bug in the examples/generic_assocaitions/discriminator_on_association.py
|
||||
Fixed a bug in the examples/generic_associations/discriminator_on_association.py
|
||||
example, where the subclasses of AddressAssociation were not being
|
||||
mapped as "single table inheritance", leading to problems when trying
|
||||
to use the mappings further.
|
||||
@@ -705,7 +708,6 @@
|
||||
.. change::
|
||||
:tags: bug, ext
|
||||
:versions: 1.0.0b1
|
||||
:pullrequest: bitbucket:28
|
||||
|
||||
Fixed bug where :class:`.ext.mutable.MutableDict`
|
||||
failed to implement the ``update()`` dictionary method, thus
|
||||
@@ -714,7 +716,6 @@
|
||||
.. change::
|
||||
:tags: bug, ext
|
||||
:versions: 1.0.0b1
|
||||
:pullrequest: bitbucket:27
|
||||
|
||||
Fixed bug where a custom subclass of :class:`.ext.mutable.MutableDict`
|
||||
would not show up in a "coerce" operation, and would instead
|
||||
@@ -735,7 +736,6 @@
|
||||
.. change::
|
||||
:tags: feature, postgresql, pg8000
|
||||
:versions: 1.0.0b1
|
||||
:pullreq: github:125
|
||||
|
||||
Support is added for "sane multi row count" with the pg8000 driver,
|
||||
which applies mostly to when using versioning with the ORM.
|
||||
@@ -759,7 +759,7 @@
|
||||
:versions: 1.0.0b1
|
||||
:tickets: 3159
|
||||
|
||||
Fixed bug where Postgresql JSON type was not able to persist or
|
||||
Fixed bug where PostgreSQL JSON type was not able to persist or
|
||||
otherwise render a SQL NULL column value, rather than a JSON-encoded
|
||||
``'null'``. To support this case, changes are as follows:
|
||||
|
||||
@@ -768,7 +768,7 @@
|
||||
|
||||
* A new parameter :paramref:`.JSON.none_as_null` is added, which
|
||||
when True indicates that the Python ``None`` value should be
|
||||
peristed as SQL NULL, rather than JSON-encoded ``'null'``.
|
||||
persisted as SQL NULL, rather than JSON-encoded ``'null'``.
|
||||
|
||||
Retrival of NULL as None is also repaired for DBAPIs other than
|
||||
psycopg2, namely pg8000.
|
||||
@@ -806,7 +806,6 @@
|
||||
:tags: bug, postgresql
|
||||
:versions: 1.0.0b1
|
||||
:tickets: 3141
|
||||
:pullreq: github:124
|
||||
|
||||
Fixed bug in :class:`.postgresql.array` object where comparison
|
||||
to a plain Python list would fail to use the correct array constructor.
|
||||
@@ -880,7 +879,7 @@
|
||||
then force all :class:`.Boolean` and :class:`.Enum` types to
|
||||
require names as well, as these implicitly create a
|
||||
constraint, even if the ultimate target backend were one that does
|
||||
not require generation of the constraint such as Postgresql.
|
||||
not require generation of the constraint such as PostgreSQL.
|
||||
The mechanics of naming conventions for these particular
|
||||
constraints has been reorganized such that the naming
|
||||
determination is done at DDL compile time, rather than at
|
||||
@@ -966,7 +965,6 @@
|
||||
.. change::
|
||||
:tags: feature, postgresql
|
||||
:versions: 1.0.0b1
|
||||
:pullreq: bitbucket:22
|
||||
:tickets: 3078
|
||||
|
||||
Added kw argument ``postgresql_regconfig`` to the
|
||||
@@ -977,14 +975,12 @@
|
||||
.. change::
|
||||
:tags: feature, postgresql
|
||||
:versions: 1.0.0b1
|
||||
:pullreq: github:101
|
||||
|
||||
Added support for Postgresql JSONB via :class:`.JSONB`. Pull request
|
||||
Added support for PostgreSQL JSONB via :class:`.JSONB`. Pull request
|
||||
courtesy Damian Dimmich.
|
||||
|
||||
.. change::
|
||||
:tags: feature, mssql
|
||||
:pullreq: github:98
|
||||
:versions: 1.0.0b1
|
||||
|
||||
Enabled "multivalues insert" for SQL Server 2008. Pull request
|
||||
@@ -1037,7 +1033,7 @@
|
||||
|
||||
Fixed bug when the declarative ``__abstract__`` flag was not being
|
||||
distinguished for when it was actually the value ``False``.
|
||||
The ``__abstract__`` flag needs to acutally evaluate to a True
|
||||
The ``__abstract__`` flag needs to actually evaluate to a True
|
||||
value at the level being tested.
|
||||
|
||||
.. changelog::
|
||||
@@ -1092,7 +1088,7 @@
|
||||
:tickets: 3002
|
||||
:versions: 1.0.0b1
|
||||
|
||||
Added a new type :class:`.postgresql.OID` to the Postgresql dialect.
|
||||
Added a new type :class:`.postgresql.OID` to the PostgreSQL dialect.
|
||||
While "oid" is generally a private type within PG that is not exposed
|
||||
in modern versions, there are some PG use cases such as large object
|
||||
support where these types might be exposed, as well as within some
|
||||
@@ -1113,7 +1109,6 @@
|
||||
|
||||
.. change::
|
||||
:tags: feature, examples
|
||||
:pullreq: bitbucket:21
|
||||
:versions: 1.0.0b1
|
||||
|
||||
Added a new example illustrating materialized paths, using the
|
||||
@@ -1121,10 +1116,9 @@
|
||||
|
||||
.. change::
|
||||
:tags: bug, testsuite
|
||||
:pullreq: github:95
|
||||
:versions: 1.0.0b1
|
||||
|
||||
In public test suite, shanged to use of ``String(40)`` from
|
||||
In public test suite, changed to use of ``String(40)`` from
|
||||
less-supported ``Text`` in ``StringTest.test_literal_backslashes``.
|
||||
Pullreq courtesy Jan.
|
||||
|
||||
@@ -1145,7 +1139,6 @@
|
||||
.. change::
|
||||
:tags: feature, postgresql
|
||||
:versions: 1.0.0b1
|
||||
:pullreq: github:88
|
||||
|
||||
Added support for AUTOCOMMIT isolation level when using the pg8000
|
||||
DBAPI. Pull request courtesy Tony Locke.
|
||||
@@ -1154,7 +1147,6 @@
|
||||
:tags: bug, postgresql
|
||||
:tickets: 3021
|
||||
:versions: 1.0.0b1
|
||||
:pullreq: github:87
|
||||
|
||||
The psycopg2 ``.closed`` accessor is now consulted when determining
|
||||
if an exception is a "disconnect" error; ideally, this should remove
|
||||
@@ -1174,7 +1166,7 @@
|
||||
in some cases a scalar attribute set to None, may not be detected
|
||||
as a net change in value, and therefore the UPDATE would not reset
|
||||
what was on the previous row. This is due to some as-yet
|
||||
unresovled side effects of the way attribute history works in terms
|
||||
unresolved side effects of the way attribute history works in terms
|
||||
of implicitly assuming None isn't really a "change" for a previously
|
||||
un-set attribute. See also :ticket:`3061`.
|
||||
|
||||
@@ -1217,14 +1209,13 @@
|
||||
.. change::
|
||||
:tags: feature, postgresql
|
||||
:tickets: 2785
|
||||
:pullreq: bitbucket:18
|
||||
:versions: 1.0.0b1
|
||||
|
||||
Added a new flag :paramref:`.ARRAY.zero_indexes` to the Postgresql
|
||||
Added a new flag :paramref:`.ARRAY.zero_indexes` to the PostgreSQL
|
||||
:class:`.ARRAY` type. When set to ``True``, a value of one will be
|
||||
added to all array index values before passing to the database, allowing
|
||||
better interoperability between Python style zero-based indexes and
|
||||
Postgresql one-based indexes. Pull request courtesy Alexey Terentev.
|
||||
PostgreSQL one-based indexes. Pull request courtesy Alexey Terentev.
|
||||
|
||||
.. change::
|
||||
:tags: bug, engine
|
||||
@@ -1309,7 +1300,6 @@
|
||||
.. change::
|
||||
:tags: bug, py3k, tests
|
||||
:tickets: 2830
|
||||
:pullreq: bitbucket:2830
|
||||
:versions: 1.0.0b1
|
||||
|
||||
Corrected for some deprecation warnings involving the ``imp``
|
||||
@@ -1362,7 +1352,7 @@
|
||||
Added new flag :paramref:`.expression.between.symmetric`, when set to True
|
||||
renders "BETWEEN SYMMETRIC". Also added a new negation operator
|
||||
"notbetween_op", which now allows an expression like ``~col.between(x, y)``
|
||||
to render as "col NOT BETWEEN x AND y", rather than a parentheiszed NOT
|
||||
to render as "col NOT BETWEEN x AND y", rather than a parenthesized NOT
|
||||
string.
|
||||
|
||||
.. changelog::
|
||||
@@ -1380,7 +1370,7 @@
|
||||
(except when version_id is used) to support the unusual edge case of
|
||||
self-referential ON DELETE CASCADE; to accommodate this, the message
|
||||
is now just a warning, not an exception, and the flag can be used
|
||||
to indicate a mapping that expects self-refererntial cascaded
|
||||
to indicate a mapping that expects self-referential cascaded
|
||||
deletes of this nature. See also :ticket:`2403` for background on the
|
||||
original change.
|
||||
|
||||
@@ -1496,7 +1486,6 @@
|
||||
.. change::
|
||||
:tags: bug, sql
|
||||
:tickets: 2988
|
||||
:pullreq: github:78
|
||||
|
||||
Fixed an 0.9 regression where a :class:`.Table` that failed to
|
||||
reflect correctly wouldn't be removed from the parent
|
||||
@@ -1575,13 +1564,12 @@
|
||||
.. change::
|
||||
:tags: feature, oracle
|
||||
:tickets: 2911
|
||||
:pullreq: github:74
|
||||
|
||||
Added a new engine option ``coerce_to_unicode=True`` to the
|
||||
cx_Oracle dialect, which restores the cx_Oracle outputtypehandler
|
||||
approach to Python unicode conversion under Python 2, which was
|
||||
removed in 0.9.2 as a result of :ticket:`2911`. Some use cases would
|
||||
prefer that unicode coersion is unconditional for all string values,
|
||||
prefer that unicode coercion is unconditional for all string values,
|
||||
despite performance concerns. Pull request courtesy
|
||||
Christoph Zwerschke.
|
||||
|
||||
@@ -1620,7 +1608,7 @@
|
||||
with pytest.
|
||||
|
||||
The test plugin system has also been enhanced to support running
|
||||
tests against mutiple database URLs at once, by specifying the ``--db``
|
||||
tests against multiple database URLs at once, by specifying the ``--db``
|
||||
and/or ``--dburi`` flags multiple times. This does not run the entire test
|
||||
suite for each database, but instead allows test cases that are specific
|
||||
to certain backends make use of that backend as the test is run.
|
||||
@@ -1796,7 +1784,6 @@
|
||||
|
||||
.. change::
|
||||
:tags: sqlite, bug
|
||||
:pullreq: github:65
|
||||
|
||||
Support has been added to SQLite type reflection to fully support
|
||||
the "type affinity" contract specified at http://www.sqlite.org/datatype3.html.
|
||||
@@ -1810,14 +1797,12 @@
|
||||
|
||||
.. change::
|
||||
:tags: postgresql, feature
|
||||
:pullreq: github:64
|
||||
|
||||
Added the :attr:`.TypeEngine.python_type` convenience accessor onto the
|
||||
:class:`.postgresql.ARRAY` type. Pull request courtesy Alexey Terentev.
|
||||
|
||||
.. change::
|
||||
:tags: examples, feature
|
||||
:pullreq: github:41
|
||||
|
||||
Added optional "changed" column to the versioned rows example, as well
|
||||
as support for when the versioned :class:`.Table` has an explicit
|
||||
@@ -1841,7 +1826,7 @@
|
||||
fully usable within declarative relationship configuration, as its
|
||||
string classname would not be available in the registry of classnames
|
||||
at mapper configuration time. The class now explicitly adds itself
|
||||
to the class regsitry, and additionally both :class:`.AbstractConcreteBase`
|
||||
to the class registry, and additionally both :class:`.AbstractConcreteBase`
|
||||
as well as :class:`.ConcreteBase` set themselves up *before* mappers
|
||||
are configured within the :func:`.configure_mappers` setup, using
|
||||
the new :meth:`.MapperEvents.before_configured` event.
|
||||
@@ -1857,7 +1842,6 @@
|
||||
.. change::
|
||||
:tags: bug, mysql, cymysql
|
||||
:tickets: 2934
|
||||
:pullreq: github:69
|
||||
|
||||
Fixed bug in cymysql dialect where a version string such as
|
||||
``'33a-MariaDB'`` would fail to parse properly. Pull request
|
||||
@@ -1870,7 +1854,7 @@
|
||||
Fixed an 0.9 regression where ORM instance or mapper events applied
|
||||
to a base class such as a declarative base with the propagate=True
|
||||
flag would fail to apply to existing mapped classes which also
|
||||
used inheritance due to an assertion. Addtionally, repaired an
|
||||
used inheritance due to an assertion. Additionally, repaired an
|
||||
attribute error which could occur during removal of such an event,
|
||||
depending on how it was first assigned.
|
||||
|
||||
@@ -1886,7 +1870,6 @@
|
||||
|
||||
.. change::
|
||||
:tags: bug, sql
|
||||
:pullreq: github:67
|
||||
|
||||
Fixed regression in new "naming convention" feature where conventions
|
||||
would fail if the referred table in a foreign key contained a schema
|
||||
@@ -1946,7 +1929,7 @@
|
||||
Added a new dialect-level argument ``postgresql_ignore_search_path``;
|
||||
this argument is accepted by both the :class:`.Table` constructor
|
||||
as well as by the :meth:`.MetaData.reflect` method. When in use
|
||||
against Postgresql, a foreign-key referenced table which specifies
|
||||
against PostgreSQL, a foreign-key referenced table which specifies
|
||||
a remote schema name will retain that schema name even if the name
|
||||
is present in the ``search_path``; the default behavior since 0.7.3
|
||||
has been that schemas present in ``search_path`` would not be copied
|
||||
@@ -2036,7 +2019,6 @@
|
||||
|
||||
:ref:`relationship_custom_operator`
|
||||
|
||||
|
||||
.. change::
|
||||
:tags: bug, sqlite
|
||||
|
||||
@@ -2177,7 +2159,6 @@
|
||||
|
||||
.. change::
|
||||
:tags: bug, sql
|
||||
:pullreq: bitbucket:11
|
||||
|
||||
A :class:`.UniqueConstraint` created inline with a :class:`.Table`
|
||||
that has no columns within it will be skipped. Pullreq courtesy
|
||||
@@ -2185,7 +2166,6 @@
|
||||
|
||||
.. change::
|
||||
:tags: feature, mssql
|
||||
:pullreq: bitbucket:11
|
||||
|
||||
Added an option ``mssql_clustered`` to the :class:`.UniqueConstraint`
|
||||
and :class:`.PrimaryKeyConstraint` constructs; on SQL Server, this adds
|
||||
@@ -2312,7 +2292,7 @@
|
||||
:tags: feature, pool, engine
|
||||
|
||||
Added a new pool event :meth:`.PoolEvents.invalidate`. Called when
|
||||
a DBAPI connection is to be marked as "invaldated" and discarded
|
||||
a DBAPI connection is to be marked as "invalidated" and discarded
|
||||
from the pool.
|
||||
|
||||
.. change::
|
||||
@@ -2327,7 +2307,6 @@
|
||||
|
||||
.. change::
|
||||
:tags: bug, py3k, cextensions
|
||||
:pullreq: github:55
|
||||
|
||||
Fixed an issue where the C extensions in Py3K are using the wrong API
|
||||
to specify the top-level module function, which breaks
|
||||
@@ -2338,7 +2317,6 @@
|
||||
|
||||
.. change::
|
||||
:tags: bug, schema
|
||||
:pullreq: github:57
|
||||
|
||||
Restored :class:`sqlalchemy.schema.SchemaVisitor` to the ``.schema``
|
||||
module. Pullreq courtesy Sean Dague.
|
||||
@@ -2407,7 +2385,6 @@
|
||||
|
||||
.. change::
|
||||
:tags: bug, orm
|
||||
:pullreq: bitbucket:9
|
||||
|
||||
Fixed bug where using new :attr:`.Session.info` attribute would fail
|
||||
if the ``.info`` argument were only passed to the :class:`.sessionmaker`
|
||||
@@ -2487,9 +2464,8 @@
|
||||
.. change::
|
||||
:tags: feature, postgresql
|
||||
:tickets: 2581
|
||||
:pullreq: github:50
|
||||
|
||||
Support for Postgresql JSON has been added, using the new
|
||||
Support for PostgreSQL JSON has been added, using the new
|
||||
:class:`.JSON` type. Huge thanks to Nathan Rice for
|
||||
implementing and testing this.
|
||||
|
||||
@@ -2537,9 +2513,8 @@
|
||||
|
||||
.. change::
|
||||
:tags: feature, postgresql
|
||||
:pullreq: bitbucket:8
|
||||
|
||||
Added support for Postgresql TSVECTOR via the
|
||||
Added support for PostgreSQL TSVECTOR via the
|
||||
:class:`.postgresql.TSVECTOR` type. Pull request courtesy
|
||||
Noufal Ibrahim.
|
||||
|
||||
@@ -2598,7 +2573,6 @@
|
||||
|
||||
.. change::
|
||||
:tags: bug, orm, collections, py3k
|
||||
:pullreq: github:40
|
||||
|
||||
Added support for the Python 3 method ``list.clear()`` within
|
||||
the ORM collection instrumentation system; pull request
|
||||
@@ -2641,7 +2615,6 @@
|
||||
|
||||
.. change::
|
||||
:tags: feature, sql
|
||||
:pullreq: github:42
|
||||
|
||||
A new API for specifying the ``FOR UPDATE`` clause of a ``SELECT``
|
||||
is added with the new :meth:`.GenerativeSelect.with_for_update` method.
|
||||
@@ -2658,7 +2631,6 @@
|
||||
|
||||
.. change::
|
||||
:tags: feature, orm
|
||||
:pullreq: github:42
|
||||
|
||||
A new API for specifying the ``FOR UPDATE`` clause of a ``SELECT``
|
||||
is added with the new :meth:`.Query.with_for_update` method,
|
||||
@@ -2676,7 +2648,7 @@
|
||||
The :func:`.create_engine` routine and the related
|
||||
:func:`.make_url` function no longer considers the ``+`` sign
|
||||
to be a space within the password field. The parsing has been
|
||||
adjuted to match RFC 1738 exactly, in that both ``username``
|
||||
adjusted to match RFC 1738 exactly, in that both ``username``
|
||||
and ``password`` expect only ``:``, ``@``, and ``/`` to be
|
||||
encoded.
|
||||
|
||||
@@ -2695,7 +2667,7 @@
|
||||
adaptation which goes on has been made more robust, such that if a descriptor
|
||||
returns another instrumented attribute, rather than a compound SQL
|
||||
expression element, the operation will still proceed.
|
||||
Addtionally, the "adapted" operator will retain its class; previously,
|
||||
Additionally, the "adapted" operator will retain its class; previously,
|
||||
a change in class from ``InstrumentedAttribute`` to ``QueryableAttribute``
|
||||
(a superclass) would interact with Python's operator system such that
|
||||
an expression like ``aliased(MyClass.x) > MyClass.x`` would reverse itself
|
||||
@@ -2814,9 +2786,9 @@
|
||||
:tags: feature, sql, postgresql, mysql
|
||||
:tickets: 2183
|
||||
|
||||
The Postgresql and MySQL dialects now support reflection/inspection
|
||||
of foreign key options, including ON UPDATE, ON DELETE. Postgresql
|
||||
also reflects MATCH, DEFERRABLE, and INITIALLY. Coutesy ijl.
|
||||
The PostgreSQL and MySQL dialects now support reflection/inspection
|
||||
of foreign key options, including ON UPDATE, ON DELETE. PostgreSQL
|
||||
also reflects MATCH, DEFERRABLE, and INITIALLY. Courtesy ijl.
|
||||
|
||||
.. change::
|
||||
:tags: bug, mysql
|
||||
@@ -2925,7 +2897,7 @@
|
||||
|
||||
Added support for rendering ``SMALLSERIAL`` when a :class:`.SmallInteger`
|
||||
type is used on a primary key autoincrement column, based on server
|
||||
version detection of Postgresql version 9.2 or greater.
|
||||
version detection of PostgreSQL version 9.2 or greater.
|
||||
|
||||
.. change::
|
||||
:tags: feature, mysql
|
||||
@@ -3058,7 +3030,7 @@
|
||||
to rely upon server generated version identifiers, using triggers
|
||||
or other database-provided versioning features, or via an optional programmatic
|
||||
value, by setting ``version_id_generator=False``.
|
||||
When using a server-generated version identfier, the ORM will use RETURNING when
|
||||
When using a server-generated version identifier, the ORM will use RETURNING when
|
||||
available to immediately
|
||||
load the new version value, else it will emit a second SELECT.
|
||||
|
||||
|
||||
Vendored
+978
-56
File diff suppressed because it is too large
Load Diff
Vendored
+2740
File diff suppressed because it is too large
Load Diff
Vendored
+2894
File diff suppressed because it is too large
Load Diff
Vendored
+950
@@ -0,0 +1,950 @@
|
||||
=============
|
||||
1.3 Changelog
|
||||
=============
|
||||
|
||||
.. changelog_imports::
|
||||
|
||||
.. include:: changelog_12.rst
|
||||
:start-line: 5
|
||||
|
||||
.. include:: changelog_11.rst
|
||||
:start-line: 5
|
||||
|
||||
.. changelog::
|
||||
:version: 1.3.2
|
||||
:include_notes_from: unreleased_13
|
||||
|
||||
.. changelog::
|
||||
:version: 1.3.1
|
||||
:released: March 9, 2019
|
||||
|
||||
.. change::
|
||||
:tags: bug, mssql
|
||||
:tickets: 4525
|
||||
|
||||
Fixed regression in SQL Server reflection due to :ticket:`4393` where the
|
||||
removal of open-ended ``**kw`` from the :class:`.Float` datatype caused
|
||||
reflection of this type to fail due to a "scale" argument being passed.
|
||||
|
||||
.. change::
|
||||
:tags: bug, orm, ext
|
||||
:tickets: 4522
|
||||
|
||||
Fixed regression where an association proxy linked to a synonym would no
|
||||
longer work, both at instance level and at class level.
|
||||
|
||||
.. changelog::
|
||||
:version: 1.3.0
|
||||
:released: March 4, 2019
|
||||
|
||||
.. change::
|
||||
:tags: feature, schema
|
||||
:tickets: 4517
|
||||
|
||||
Added new parameters :paramref:`.Table.resolve_fks` and
|
||||
:paramref:`.MetaData.reflect.resolve_fks` which when set to False will
|
||||
disable the automatic reflection of related tables encountered in
|
||||
:class:`.ForeignKey` objects, which can both reduce SQL overhead for omitted
|
||||
tables as well as avoid tables that can't be reflected for database-specific
|
||||
reasons. Two :class:`.Table` objects present in the same :class:`.MetaData`
|
||||
collection can still refer to each other even if the reflection of the two
|
||||
tables occurred separately.
|
||||
|
||||
|
||||
.. change::
|
||||
:tags: feature, orm
|
||||
:tickets: 4316
|
||||
|
||||
The :meth:`.Query.get` method can now accept a dictionary of attribute keys
|
||||
and values as a means of indicating the primary key value to load; is
|
||||
particularly useful for composite primary keys. Pull request courtesy
|
||||
Sanjana S.
|
||||
|
||||
.. change::
|
||||
:tags: feature, orm
|
||||
:tickets: 3133
|
||||
|
||||
A SQL expression can now be assigned to a primary key attribute for an ORM
|
||||
flush in the same manner as ordinary attributes as described in
|
||||
:ref:`flush_embedded_sql_expressions` where the expression will be evaulated
|
||||
and then returned to the ORM using RETURNING, or in the case of pysqlite,
|
||||
works using the cursor.lastrowid attribute.Requires either a database that
|
||||
supports RETURNING (e.g. Postgresql, Oracle, SQL Server) or pysqlite.
|
||||
|
||||
.. change::
|
||||
:tags: bug, sql
|
||||
:tickets: 4509
|
||||
|
||||
The :class:`.Alias` class and related subclasses :class:`.CTE`,
|
||||
:class:`.Lateral` and :class:`.TableSample` have been reworked so that it is
|
||||
not possible for a user to construct the objects directly. These constructs
|
||||
require that the standalone construction function or selectable-bound method
|
||||
be used to instantiate new objects.
|
||||
|
||||
|
||||
.. change::
|
||||
:tags: feature, engine
|
||||
:tickets: 4500
|
||||
|
||||
Revised the formatting for :class:`.StatementError` when stringified. Each
|
||||
error detail is broken up over multiple newlines instead of spaced out on a
|
||||
single line. Additionally, the SQL representation now stringifies the SQL
|
||||
statement rather than using ``repr()``, so that newlines are rendered as is.
|
||||
Pull request courtesy Nate Clark.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_4500`
|
||||
|
||||
.. changelog::
|
||||
:version: 1.3.0b3
|
||||
:released: March 4, 2019
|
||||
:released: February 8, 2019
|
||||
|
||||
.. change::
|
||||
:tags: bug, ext
|
||||
:tickets: 2642
|
||||
|
||||
Implemented a more comprehensive assignment operation (e.g. "bulk replace")
|
||||
when using association proxy with sets or dictionaries. Fixes the problem
|
||||
of redundant proxy objects being created to replace the old ones, which
|
||||
leads to excessive events and SQL and in the case of unique constraints
|
||||
will cause the flush to fail.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_2642`
|
||||
|
||||
.. change::
|
||||
:tags: bug, postgresql
|
||||
:tickets: 4473
|
||||
|
||||
Fixed issue where using an uppercase name for an index type (e.g. GIST,
|
||||
BTREE, etc. ) or an EXCLUDE constraint would treat it as an identifier to
|
||||
be quoted, rather than rendering it as is. The new behavior converts these
|
||||
types to lowercase and ensures they contain only valid SQL characters.
|
||||
|
||||
.. change::
|
||||
:tags: bug, orm
|
||||
:tickets: 4469
|
||||
|
||||
Improved the behavior of :func:`.orm.with_polymorphic` in conjunction with
|
||||
loader options, in particular wildcard operations as well as
|
||||
:func:`.orm.load_only`. The polymorphic object will be more accurately
|
||||
targeted so that column-level options on the entity will correctly take
|
||||
effect.The issue is a continuation of the same kinds of things fixed in
|
||||
:ticket:`4468`.
|
||||
|
||||
|
||||
.. change::
|
||||
:tags: bug, sql
|
||||
:tickets: 4481
|
||||
|
||||
Fully removed the behavior of strings passed directly as components of a
|
||||
:func:`.select` or :class:`.Query` object being coerced to :func:`.text`
|
||||
constructs automatically; the warning that has been emitted is now an
|
||||
ArgumentError or in the case of order_by() / group_by() a CompileError.
|
||||
This has emitted a warning since version 1.0 however its presence continues
|
||||
to create concerns for the potential of mis-use of this behavior.
|
||||
|
||||
Note that public CVEs have been posted for order_by() / group_by() which
|
||||
are resolved by this commit: CVE-2019-7164 CVE-2019-7548
|
||||
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_4481`
|
||||
|
||||
.. change::
|
||||
:tags: bug, sql
|
||||
:tickets: 4467
|
||||
|
||||
Quoting is applied to :class:`.Function` names, those which are usually but
|
||||
not necessarily generated from the :attr:`.sql.func` construct, at compile
|
||||
time if they contain illegal characters, such as spaces or punctuation. The
|
||||
names are as before treated as case insensitive however, meaning if the
|
||||
names contain uppercase or mixed case characters, that alone does not
|
||||
trigger quoting. The case insensitivity is currently maintained for
|
||||
backwards compatibility.
|
||||
|
||||
|
||||
.. change::
|
||||
:tags: bug, sql
|
||||
:tickets: 4481
|
||||
|
||||
Added "SQL phrase validation" to key DDL phrases that are accepted as plain
|
||||
strings, including :paramref:`.ForeignKeyConstraint.on_delete`,
|
||||
:paramref:`.ForeignKeyConstraint.on_update`,
|
||||
:paramref:`.ExcludeConstraint.using`,
|
||||
:paramref:`.ForeignKeyConstraint.initially`, for areas where a series of SQL
|
||||
keywords only are expected.Any non-space characters that suggest the phrase
|
||||
would need to be quoted will raise a :class:`.CompileError`. This change
|
||||
is related to the series of changes committed as part of :ticket:`4481`.
|
||||
|
||||
.. change::
|
||||
:tags: bug, orm, declarative
|
||||
:tickets: 4470
|
||||
|
||||
Added some helper exceptions that invoke when a mapping based on
|
||||
:class:`.AbstractConcreteBase`, :class:`.DeferredReflection`, or
|
||||
:class:`.AutoMap` is used before the mapping is ready to be used, which
|
||||
contain descriptive information on the class, rather than falling through
|
||||
into other failure modes that are less informative.
|
||||
|
||||
|
||||
.. change::
|
||||
:tags: change, tests
|
||||
:tickets: 4460
|
||||
|
||||
The test system has removed support for Nose, which is unmaintained for
|
||||
several years and is producing warnings under Python 3. The test suite is
|
||||
currently standardized on Pytest. Pull request courtesy Parth Shandilya.
|
||||
|
||||
.. changelog::
|
||||
:version: 1.3.0b2
|
||||
:released: March 4, 2019
|
||||
:released: January 25, 2019
|
||||
|
||||
.. change::
|
||||
:tags: bug, ext
|
||||
:tickets: 4401
|
||||
|
||||
Fixed a regression in 1.3.0b1 caused by :ticket:`3423` where association
|
||||
proxy objects that access an attribute that's only present on a polymorphic
|
||||
subclass would raise an ``AttributeError`` even though the actual instance
|
||||
being accessed was an instance of that subclass.
|
||||
|
||||
.. change::
|
||||
:tags: bug, orm
|
||||
:tickets: 1103
|
||||
|
||||
Fixed long-standing issue where duplicate collection members would cause a
|
||||
backref to delete the association between the member and its parent object
|
||||
when one of the duplicates were removed, as occurs as a side effect of
|
||||
swapping two objects in one statement.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_1103`
|
||||
|
||||
.. change::
|
||||
:tags: bug, mssql
|
||||
:tickets: 4442
|
||||
|
||||
The ``literal_processor`` for the :class:`.Unicode` and
|
||||
:class:`.UnicodeText` datatypes now render an ``N`` character in front of
|
||||
the literal string expression as required by SQL Server for Unicode string
|
||||
values rendered in SQL expressions.
|
||||
|
||||
.. change::
|
||||
:tags: feature, orm
|
||||
:tickets: 4423
|
||||
|
||||
Implemented a new feature whereby the :class:`.AliasedClass` construct can
|
||||
now be used as the target of a :func:`.relationship`. This allows the
|
||||
concept of "non primary mappers" to no longer be necessary, as the
|
||||
:class:`.AliasedClass` is much easier to configure and automatically inherits
|
||||
all the relationships of the mapped class, as well as preserves the
|
||||
ability for loader options to work normally.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_4423`
|
||||
|
||||
.. change::
|
||||
:tags: bug, orm
|
||||
:tickets: 4373
|
||||
|
||||
Extended the fix first made as part of :ticket:`3287`, where a loader option
|
||||
made against a subclass using a wildcard would extend itself to include
|
||||
application of the wildcard to attributes on the super classes as well, to a
|
||||
"bound" loader option as well, e.g. in an expression like
|
||||
``Load(SomeSubClass).load_only('foo')``. Columns that are part of the
|
||||
parent class of ``SomeSubClass`` will also be excluded in the same way as if
|
||||
the unbound option ``load_only('foo')`` were used.
|
||||
|
||||
.. change::
|
||||
:tags: bug, orm
|
||||
:tickets: 4433
|
||||
|
||||
Improved error messages emitted by the ORM in the area of loader option
|
||||
traversal. This includes early detection of mis-matched loader strategies
|
||||
along with a clearer explanation why these strategies don't match.
|
||||
|
||||
|
||||
.. change::
|
||||
:tags: change, orm
|
||||
:tickets: 4412
|
||||
|
||||
Added a new function :func:`.close_all_sessions` which takes
|
||||
over the task of the :meth:`.Session.close_all` method, which
|
||||
is now deprecated as this is confusing as a classmethod.
|
||||
Pull request courtesy Augustin Trancart.
|
||||
|
||||
.. change::
|
||||
:tags: feature, orm
|
||||
:tickets: 4397
|
||||
|
||||
Added new :meth:`.MapperEvents.before_mapper_configured` event. This
|
||||
event complements the other "configure" stage mapper events with a per
|
||||
mapper event that receives each :class:`.Mapper` right before its
|
||||
configure step, and additionally may be used to prevent or delay the
|
||||
configuration of specific :class:`.Mapper` objects using a new
|
||||
return value :attr:`.orm.interfaces.EXT_SKIP`. See the
|
||||
documentation link for an example.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:meth:`.MapperEvents.before_mapper_configured`
|
||||
|
||||
|
||||
|
||||
.. change::
|
||||
:tags: bug, orm
|
||||
|
||||
The "remove" event for collections is now called before the item is removed
|
||||
in the case of the ``collection.remove()`` method, as is consistent with the
|
||||
behavior for most other forms of collection item removal (such as
|
||||
``__delitem__``, replacement under ``__setitem__``). For ``pop()`` methods,
|
||||
the remove event still fires after the operation.
|
||||
|
||||
.. change::
|
||||
:tags: bug, orm declarative
|
||||
:tickets: 4372
|
||||
|
||||
Added a ``__clause_element__()`` method to :class:`.ColumnProperty` which
|
||||
can allow the usage of a not-fully-declared column or deferred attribute in
|
||||
a declarative mapped class slightly more friendly when it's used in a
|
||||
constraint or other column-oriented scenario within the class declaration,
|
||||
though this still can't work in open-ended expressions; prefer to call the
|
||||
:attr:`.ColumnProperty.expression` attribute if receiving ``TypeError``.
|
||||
|
||||
.. change::
|
||||
:tags: bug, orm, engine
|
||||
:tickets: 4464
|
||||
|
||||
Added accessors for execution options to Core and ORM, via
|
||||
:meth:`.Query.get_execution_options`,
|
||||
:meth:`.Connection.get_execution_options`,
|
||||
:meth:`.Engine.get_execution_options`, and
|
||||
:meth:`.Executable.get_execution_options`. PR courtesy Daniel Lister.
|
||||
|
||||
.. change::
|
||||
:tags: bug, orm
|
||||
:tickets: 4446
|
||||
|
||||
Fixed issue in association proxy due to :ticket:`3423` which caused the use
|
||||
of custom :class:`.PropComparator` objects with hybrid attribites, such as
|
||||
the one demonstrated in the ``dictlike-polymorphic`` example to not
|
||||
function within an association proxy. The strictness that was added in
|
||||
:ticket:`3423` has been relaxed, and additional logic to accomodate for
|
||||
an association proxy that links to a custom hybrid have been added.
|
||||
|
||||
.. change::
|
||||
:tags: change, general
|
||||
:tickets: 4393
|
||||
|
||||
A large change throughout the library has ensured that all objects,
|
||||
parameters, and behaviors which have been noted as deprecated or legacy now
|
||||
emit ``DeprecationWarning`` warnings when invoked.As the Python 3
|
||||
interpreter now defaults to displaying deprecation warnings, as well as that
|
||||
modern test suites based on tools like tox and pytest tend to display
|
||||
deprecation warnings, this change should make it easier to note what API
|
||||
features are obsolete. A major rationale for this change is so that long-
|
||||
deprecated features that nonetheless still see continue to see real world
|
||||
use can finally be removed in the near future; the biggest example of this
|
||||
are the :class:`.SessionExtension` and :class:`.MapperExtension` classes as
|
||||
well as a handful of other pre-event extension hooks, which have been
|
||||
deprecated since version 0.7 but still remain in the library. Another is
|
||||
that several major longstanding behaviors are to be deprecated as well,
|
||||
including the threadlocal engine strategy, the convert_unicode flag, and non
|
||||
primary mappers.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_4393_general`
|
||||
|
||||
|
||||
.. change::
|
||||
:tags: change, engine
|
||||
:tickets: 4393
|
||||
|
||||
The "threadlocal" engine strategy which has been a legacy feature of
|
||||
SQLAlchemy since around version 0.2 is now deprecated, along with the
|
||||
:paramref:`.Pool.threadlocal` parameter of :class:`.Pool` which has no
|
||||
effect in most modern use cases.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_4393_threadlocal`
|
||||
|
||||
.. change::
|
||||
:tags: change, sql
|
||||
:tickets: 4393
|
||||
|
||||
The :paramref:`.create_engine.convert_unicode` and
|
||||
:paramref:`.String.convert_unicode` parameters have been deprecated. These
|
||||
parameters were built back when most Python DBAPIs had little to no support
|
||||
for Python Unicode objects, and SQLAlchemy needed to take on the very
|
||||
complex task of marshalling data and SQL strings between Unicode and
|
||||
bytestrings throughout the system in a performant way. Thanks to Python 3,
|
||||
DBAPIs were compelled to adapt to Unicode-aware APIs and today all DBAPIs
|
||||
supported by SQLAlchemy support Unicode natively, including on Python 2,
|
||||
allowing this long-lived and very complicated feature to finally be (mostly)
|
||||
removed. There are still of course a few Python 2 edge cases where
|
||||
SQLAlchemy has to deal with Unicode however these are handled automatically;
|
||||
in modern use, there should be no need for end-user interaction with these
|
||||
flags.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_4393_convertunicode`
|
||||
|
||||
.. change::
|
||||
:tags: bug, orm
|
||||
:tickets: 3777
|
||||
|
||||
Implemented the ``.get_history()`` method, which also implies availability
|
||||
of :attr:`.AttributeState.history`, for :func:`.synonym` attributes.
|
||||
Previously, trying to access attribute history via a synonym would raise an
|
||||
``AttributeError``.
|
||||
|
||||
.. change::
|
||||
:tags: feature, engine
|
||||
:tickets: 3689
|
||||
|
||||
Added public accessor :meth:`.QueuePool.timeout` that returns the configured
|
||||
timeout for a :class:`.QueuePool` object. Pull request courtesy Irina Delamare.
|
||||
|
||||
.. change::
|
||||
:tags: feature, sql
|
||||
:tickets: 4386
|
||||
|
||||
Amended the :class:`.AnsiFunction` class, the base of common SQL
|
||||
functions like ``CURRENT_TIMESTAMP``, to accept positional arguments
|
||||
like a regular ad-hoc function. This to suit the case that many of
|
||||
these functions on specific backends accept arguments such as
|
||||
"fractional seconds" precision and such. If the function is created
|
||||
with arguments, it renders the parenthesis and the arguments. If
|
||||
no arguments are present, the compiler generates the non-parenthesized form.
|
||||
|
||||
.. changelog::
|
||||
:version: 1.3.0b1
|
||||
:released: March 4, 2019
|
||||
:released: November 16, 2018
|
||||
|
||||
.. change::
|
||||
:tags: bug, ext
|
||||
:tickets: 3423
|
||||
|
||||
Reworked :class:`.AssociationProxy` to store state that's specific to a
|
||||
parent class in a separate object, so that a single
|
||||
:class:`.AssocationProxy` can serve for multiple parent classes, as is
|
||||
intrinsic to inheritance, without any ambiguity in the state returned by it.
|
||||
A new method :meth:`.AssociationProxy.for_class` is added to allow
|
||||
inspection of class-specific state.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_3423`
|
||||
|
||||
|
||||
.. change::
|
||||
:tags: bug, oracle
|
||||
:tickets: 4369
|
||||
|
||||
Updated the parameters that can be sent to the cx_Oracle DBAPI to both allow
|
||||
for all current parameters as well as for future parameters not added yet.
|
||||
In addition, removed unused parameters that were deprecated in version 1.2,
|
||||
and additionally we are now defaulting "threaded" to False.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_4369`
|
||||
|
||||
.. change::
|
||||
:tags: bug, oracle
|
||||
:tickets: 4242
|
||||
|
||||
The Oracle dialect will no longer use the NCHAR/NCLOB datatypes
|
||||
represent generic unicode strings or clob fields in conjunction with
|
||||
:class:`.Unicode` and :class:`.UnicodeText` unless the flag
|
||||
``use_nchar_for_unicode=True`` is passed to :func:`.create_engine` -
|
||||
this includes CREATE TABLE behavior as well as ``setinputsizes()`` for
|
||||
bound parameters. On the read side, automatic Unicode conversion under
|
||||
Python 2 has been added to CHAR/VARCHAR/CLOB result rows, to match the
|
||||
behavior of cx_Oracle under Python 3. In order to mitigate the performance
|
||||
hit under Python 2, SQLAlchemy's very performant (when C extensions
|
||||
are built) native Unicode handlers are used under Python 2.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_4242`
|
||||
|
||||
.. change::
|
||||
:tags: bug, orm
|
||||
:tickets: 3844
|
||||
|
||||
Fixed issue regarding passive_deletes="all", where the foreign key
|
||||
attribute of an object is maintained with its value even after the object
|
||||
is removed from its parent collection. Previously, the unit of work would
|
||||
set this to NULL even though passive_deletes indicated it should not be
|
||||
modified.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_3844`
|
||||
|
||||
.. change::
|
||||
:tags: bug, ext
|
||||
:tickets: 4268
|
||||
|
||||
The long-standing behavior of the association proxy collection maintaining
|
||||
only a weak reference to the parent object is reverted; the proxy will now
|
||||
maintain a strong reference to the parent for as long as the proxy
|
||||
collection itself is also in memory, eliminating the "stale association
|
||||
proxy" error. This change is being made on an experimental basis to see if
|
||||
any use cases arise where it causes side effects.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_4268`
|
||||
|
||||
|
||||
.. change::
|
||||
:tags: bug, sql
|
||||
:tickets: 4302
|
||||
|
||||
Added "like" based operators as "comparison" operators, including
|
||||
:meth:`.ColumnOperators.startswith` :meth:`.ColumnOperators.endswith`
|
||||
:meth:`.ColumnOperators.ilike` :meth:`.ColumnOperators.notilike` among many
|
||||
others, so that all of these operators can be the basis for an ORM
|
||||
"primaryjoin" condition.
|
||||
|
||||
|
||||
.. change::
|
||||
:tags: feature, sqlite
|
||||
:tickets: 3850
|
||||
|
||||
Added support for SQLite's json functionality via the new
|
||||
SQLite implementation for :class:`.types.JSON`, :class:`.sqlite.JSON`.
|
||||
The name used for the type is ``JSON``, following an example found at
|
||||
SQLite's own documentation. Pull request courtesy Ilja Everilä.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_3850`
|
||||
|
||||
.. change::
|
||||
:tags: feature, engine
|
||||
|
||||
Added new "lifo" mode to :class:`.QueuePool`, typically enabled by setting
|
||||
the flag :paramref:`.create_engine.pool_use_lifo` to True. "lifo" mode
|
||||
means the same connection just checked in will be the first to be checked
|
||||
out again, allowing excess connections to be cleaned up from the server
|
||||
side during periods of the pool being only partially utilized. Pull request
|
||||
courtesy Taem Park.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_pr467`
|
||||
|
||||
.. change::
|
||||
:tags: bug, orm
|
||||
:tickets: 4359
|
||||
|
||||
Improved the behavior of a relationship-bound many-to-one object expression
|
||||
such that the retrieval of column values on the related object are now
|
||||
resilient against the object being detached from its parent
|
||||
:class:`.Session`, even if the attribute has been expired. New features
|
||||
within the :class:`.InstanceState` are used to memoize the last known value
|
||||
of a particular column attribute before its expired, so that the expression
|
||||
can still evaluate when the object is detached and expired at the same
|
||||
time. Error conditions are also improved using modern attribute state
|
||||
features to produce more specific messages as needed.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_4359`
|
||||
|
||||
.. change::
|
||||
:tags: feature, mysql
|
||||
:tickets: 4219
|
||||
|
||||
Support added for the "WITH PARSER" syntax of CREATE FULLTEXT INDEX
|
||||
in MySQL, using the ``mysql_with_parser`` keyword argument. Reflection
|
||||
is also supported, which accommodates MySQL's special comment format
|
||||
for reporting on this option as well. Additionally, the "FULLTEXT" and
|
||||
"SPATIAL" index prefixes are now reflected back into the ``mysql_prefix``
|
||||
index option.
|
||||
|
||||
|
||||
|
||||
.. change::
|
||||
:tags: bug, orm, mysql, postgresql
|
||||
:tickets: 4246
|
||||
|
||||
The ORM now doubles the "FOR UPDATE" clause within the subquery that
|
||||
renders in conjunction with joined eager loading in some cases, as it has
|
||||
been observed that MySQL does not lock the rows from a subquery. This
|
||||
means the query renders with two FOR UPDATE clauses; note that on some
|
||||
backends such as Oracle, FOR UPDATE clauses on subqueries are silently
|
||||
ignored since they are unnecessary. Additionally, in the case of the "OF"
|
||||
clause used primarily with PostgreSQL, the FOR UPDATE is rendered only on
|
||||
the inner subquery when this is used so that the selectable can be targeted
|
||||
to the table within the SELECT statement.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_4246`
|
||||
|
||||
.. change::
|
||||
:tags: feature, mssql
|
||||
:tickets: 4158
|
||||
|
||||
Added ``fast_executemany=True`` parameter to the SQL Server pyodbc dialect,
|
||||
which enables use of pyodbc's new performance feature of the same name
|
||||
when using Microsoft ODBC drivers.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_4158`
|
||||
|
||||
.. change::
|
||||
:tags: bug, ext
|
||||
:tickets: 4308
|
||||
|
||||
Fixed multiple issues regarding de-association of scalar objects with the
|
||||
association proxy. ``del`` now works, and additionally a new flag
|
||||
:paramref:`.AssociationProxy.cascade_scalar_deletes` is added, which when
|
||||
set to True indicates that setting a scalar attribute to ``None`` or
|
||||
deleting via ``del`` will also set the source association to ``None``.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_4308`
|
||||
|
||||
|
||||
.. change::
|
||||
:tags: feature, ext
|
||||
:tickets: 4318
|
||||
|
||||
Added new feature :meth:`.BakedQuery.to_query`, which allows for a
|
||||
clean way of using one :class:`.BakedQuery` as a subquery inside of another
|
||||
:class:`.BakedQuery` without needing to refer explicitly to a
|
||||
:class:`.Session`.
|
||||
|
||||
|
||||
.. change::
|
||||
:tags: feature, sqlite
|
||||
:tickets: 4360
|
||||
|
||||
Implemented the SQLite ``ON CONFLICT`` clause as understood at the DDL
|
||||
level, e.g. for primary key, unique, and CHECK constraints as well as
|
||||
specified on a :class:`.Column` to satisfy inline primary key and NOT NULL.
|
||||
Pull request courtesy Denis Kataev.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_4360`
|
||||
|
||||
.. change::
|
||||
:tags: feature, postgresql
|
||||
:tickets: 4237
|
||||
|
||||
Added rudimental support for reflection of PostgreSQL
|
||||
partitioned tables, e.g. that relkind='p' is added to reflection
|
||||
queries that return table information.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_4237`
|
||||
|
||||
.. change::
|
||||
:tags: feature, ext
|
||||
:tickets: 4351
|
||||
|
||||
The :class:`.AssociationProxy` now has standard column comparison operations
|
||||
such as :meth:`.ColumnOperators.like` and
|
||||
:meth:`.ColumnOperators.startswith` available when the target attribute is a
|
||||
plain column - the EXISTS expression that joins to the target table is
|
||||
rendered as usual, but the column expression is then use within the WHERE
|
||||
criteria of the EXISTS. Note that this alters the behavior of the
|
||||
``.contains()`` method on the association proxy to make use of
|
||||
:meth:`.ColumnOperators.contains` when used on a column-based attribute.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_4351`
|
||||
|
||||
|
||||
.. change::
|
||||
:tags: feature, orm
|
||||
|
||||
Added new flag :paramref:`.Session.bulk_save_objects.preserve_order` to the
|
||||
:meth:`.Session.bulk_save_objects` method, which defaults to True. When set
|
||||
to False, the given mappings will be grouped into inserts and updates per
|
||||
each object type, to allow for greater opportunities to batch common
|
||||
operations together. Pull request courtesy Alessandro Cucci.
|
||||
|
||||
.. change::
|
||||
:tags: bug, orm
|
||||
:tickets: 4365
|
||||
|
||||
Refactored :meth:`.Query.join` to further clarify the individual components
|
||||
of structuring the join. This refactor adds the ability for
|
||||
:meth:`.Query.join` to determine the most appropriate "left" side of the
|
||||
join when there is more than one element in the FROM list or the query is
|
||||
against multiple entities. If more than one FROM/entity matches, an error
|
||||
is raised that asks for an ON clause to be specified to resolve the
|
||||
ambiguity. In particular this targets the regression we saw in
|
||||
:ticket:`4363` but is also of general use. The codepaths within
|
||||
:meth:`.Query.join` are now easier to follow and the error cases are
|
||||
decided more specifically at an earlier point in the operation.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_4365`
|
||||
|
||||
.. change::
|
||||
:tags: bug, sql
|
||||
:tickets: 3981
|
||||
|
||||
Fixed issue with :meth:`.TypeEngine.bind_expression` and
|
||||
:meth:`.TypeEngine.column_expression` methods where these methods would not
|
||||
work if the target type were part of a :class:`.Variant`, or other target
|
||||
type of a :class:`.TypeDecorator`. Additionally, the SQL compiler now
|
||||
calls upon the dialect-level implementation when it renders these methods
|
||||
so that dialects can now provide for SQL-level processing for built-in
|
||||
types.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_3981`
|
||||
|
||||
|
||||
.. change::
|
||||
:tags: bug, orm
|
||||
:tickets: 4304
|
||||
|
||||
Fixed long-standing issue in :class:`.Query` where a scalar subquery such
|
||||
as produced by :meth:`.Query.exists`, :meth:`.Query.as_scalar` and other
|
||||
derivations from :attr:`.Query.statement` would not correctly be adapted
|
||||
when used in a new :class:`.Query` that required entity adaptation, such as
|
||||
when the query were turned into a union, or a from_self(), etc. The change
|
||||
removes the "no adaptation" annotation from the :func:`.select` object
|
||||
produced by the :attr:`.Query.statement` accessor.
|
||||
|
||||
.. change::
|
||||
:tags: bug, orm, declarative
|
||||
:tickets: 4133
|
||||
|
||||
Fixed bug where declarative would not update the state of the
|
||||
:class:`.Mapper` as far as what attributes were present, when additional
|
||||
attributes were added or removed after the mapper attribute collections had
|
||||
already been called and memoized. Addtionally, a ``NotImplementedError``
|
||||
is now raised if a fully mapped attribute (e.g. column, relationship, etc.)
|
||||
is deleted from a class that is currently mapped, since the mapper will not
|
||||
function correctly if the attribute has been removed.
|
||||
|
||||
.. change::
|
||||
:tags: bug, mssql
|
||||
:tickets: 4362
|
||||
|
||||
Deprecated the use of :class:`.Sequence` with SQL Server in order to affect
|
||||
the "start" and "increment" of the IDENTITY value, in favor of new
|
||||
parameters ``mssql_identity_start`` and ``mssql_identity_increment`` which
|
||||
set these parameters directly. :class:`.Sequence` will be used to generate
|
||||
real ``CREATE SEQUENCE`` DDL with SQL Server in a future release.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_4362`
|
||||
|
||||
|
||||
.. change::
|
||||
:tags: feature, mysql
|
||||
|
||||
Added support for the parameters in an ON DUPLICATE KEY UPDATE statement on
|
||||
MySQL to be ordered, since parameter order in a MySQL UPDATE clause is
|
||||
significant, in a similar manner as that described at
|
||||
:ref:`updates_order_parameters`. Pull request courtesy Maxim Bublis.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_mysql_ondupordering`
|
||||
|
||||
.. change::
|
||||
:tags: feature, sql
|
||||
:tickets: 4144
|
||||
|
||||
Added :class:`.Sequence` to the "string SQL" system that will render a
|
||||
meaningful string expression (``"<next sequence value: my_sequence>"``)
|
||||
when stringifying without a dialect a statement that includes a "sequence
|
||||
nextvalue" expression, rather than raising a compilation error.
|
||||
|
||||
|
||||
|
||||
.. change::
|
||||
:tags: bug, orm
|
||||
:tickets: 4232
|
||||
|
||||
An informative exception is re-raised when a primary key value is not
|
||||
sortable in Python during an ORM flush under Python 3, such as an ``Enum``
|
||||
that has no ``__lt__()`` method; normally Python 3 raises a ``TypeError``
|
||||
in this case. The flush process sorts persistent objects by primary key
|
||||
in Python so the values must be sortable.
|
||||
|
||||
|
||||
.. change::
|
||||
:tags: orm, bug
|
||||
:tickets: 3604
|
||||
|
||||
Removed the collection converter used by the :class:`.MappedCollection`
|
||||
class. This converter was used only to assert that the incoming dictionary
|
||||
keys matched that of their corresponding objects, and only during a bulk set
|
||||
operation. The converter can interfere with a custom validator or
|
||||
:meth:`.AttributeEvents.bulk_replace` listener that wants to convert
|
||||
incoming values further. The ``TypeError`` which would be raised by this
|
||||
converter when an incoming key didn't match the value is removed; incoming
|
||||
values during a bulk assignment will be keyed to their value-generated key,
|
||||
and not the key that's explicitly present in the dictionary.
|
||||
|
||||
Overall, @converter is superseded by the
|
||||
:meth:`.AttributeEvents.bulk_replace` event handler added as part of
|
||||
:ticket:`3896`.
|
||||
|
||||
.. change::
|
||||
:tags: feature, sql
|
||||
:tickets: 3989
|
||||
|
||||
Added new naming convention tokens ``column_0N_name``, ``column_0_N_name``,
|
||||
etc., which will render the names / keys / labels for all columns referenced
|
||||
by a particular constraint in a sequence. In order to accommodate for the
|
||||
length of such a naming convention, the SQL compiler's auto-truncation
|
||||
feature now applies itself to constraint names as well, which creates a
|
||||
shortened, deterministically generated name for the constraint that will
|
||||
apply to a target backend without going over the character limit of that
|
||||
backend.
|
||||
|
||||
The change also repairs two other issues. One is that the ``column_0_key``
|
||||
token wasn't available even though this token was documented, the other was
|
||||
that the ``referred_column_0_name`` token would inadvertently render the
|
||||
``.key`` and not the ``.name`` of the column if these two values were
|
||||
different.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_3989`
|
||||
|
||||
|
||||
.. change::
|
||||
:tags: feature, ext
|
||||
:tickets: 4196
|
||||
|
||||
Added support for bulk :meth:`.Query.update` and :meth:`.Query.delete`
|
||||
to the :class:`.ShardedQuery` class within the horizontal sharding
|
||||
extension. This also adds an additional expansion hook to the
|
||||
bulk update/delete methods :meth:`.Query._execute_crud`.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_4196`
|
||||
|
||||
.. change::
|
||||
:tags: feature, sql
|
||||
:tickets: 4271
|
||||
|
||||
Added new logic to the "expanding IN" bound parameter feature whereby if
|
||||
the given list is empty, a special "empty set" expression that is specific
|
||||
to different backends is generated, thus allowing IN expressions to be
|
||||
fully dynamic including empty IN expressions.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_4271`
|
||||
|
||||
|
||||
|
||||
.. change::
|
||||
:tags: feature, mysql
|
||||
|
||||
The "pre-ping" feature of the connection pool now uses
|
||||
the ``ping()`` method of the DBAPI connection in the case of
|
||||
mysqlclient, PyMySQL and mysql-connector-python. Pull request
|
||||
courtesy Maxim Bublis.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_mysql_ping`
|
||||
|
||||
.. change::
|
||||
:tags: feature, orm
|
||||
:tickets: 4340
|
||||
|
||||
The "selectin" loader strategy now omits the JOIN in the case of a simple
|
||||
one-to-many load, where it instead relies loads only from the related
|
||||
table, relying upon the foreign key columns of the related table in order
|
||||
to match up to primary keys in the parent table. This optimization can be
|
||||
disabled by setting the :paramref:`.relationship.omit_join` flag to False.
|
||||
Many thanks to Jayson Reis for the efforts on this.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_4340`
|
||||
|
||||
.. change::
|
||||
:tags: bug, orm
|
||||
:tickets: 4353
|
||||
|
||||
Added new behavior to the lazy load that takes place when the "old" value of
|
||||
a many-to-one is retrieved, such that exceptions which would be raised due
|
||||
to either ``lazy="raise"`` or a detached session error are skipped.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_4353`
|
||||
|
||||
.. change::
|
||||
:tags: feature, sql
|
||||
|
||||
The Python builtin ``dir()`` is now supported for a SQLAlchemy "properties"
|
||||
object, such as that of a Core columns collection (e.g. ``.c``),
|
||||
``mapper.attrs``, etc. Allows iPython autocompletion to work as well.
|
||||
Pull request courtesy Uwe Korn.
|
||||
|
||||
.. change::
|
||||
:tags: feature, orm
|
||||
:tickets: 4257
|
||||
|
||||
Added ``.info`` dictionary to the :class:`.InstanceState` class, the object
|
||||
that comes from calling :func:`.inspect` on a mapped object.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_4257`
|
||||
|
||||
.. change::
|
||||
:tags: feature, sql
|
||||
:tickets: 3831
|
||||
|
||||
Added new feature :meth:`.FunctionElement.as_comparison` which allows a SQL
|
||||
function to act as a binary comparison operation that can work within the
|
||||
ORM.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_3831`
|
||||
|
||||
.. change::
|
||||
:tags: bug, orm
|
||||
:tickets: 4354
|
||||
|
||||
A long-standing oversight in the ORM, the ``__delete__`` method for a many-
|
||||
to-one relationship was non-functional, e.g. for an operation such as ``del
|
||||
a.b``. This is now implemented and is equivalent to setting the attribute
|
||||
to ``None``.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_4354`
|
||||
Vendored
+8
-2
@@ -7,12 +7,12 @@ SQLAlchemy changelogs and migration guides are now integrated
|
||||
within the main documentation.
|
||||
|
||||
Current Migration Guide
|
||||
------------------------
|
||||
-----------------------
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
|
||||
migration_10
|
||||
migration_13
|
||||
|
||||
Change logs
|
||||
-----------
|
||||
@@ -20,6 +20,9 @@ Change logs
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
|
||||
changelog_13
|
||||
changelog_12
|
||||
changelog_11
|
||||
changelog_10
|
||||
changelog_09
|
||||
changelog_08
|
||||
@@ -38,6 +41,9 @@ Older Migration Guides
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
|
||||
migration_12
|
||||
migration_11
|
||||
migration_10
|
||||
migration_09
|
||||
migration_08
|
||||
migration_07
|
||||
|
||||
Vendored
+5
-7
@@ -412,7 +412,7 @@ flush before each query.
|
||||
foo.bars.append(Bar(name='lala'))
|
||||
|
||||
for bar in foo.bars.filter(Bar.name=='lala'):
|
||||
print bar
|
||||
print(bar)
|
||||
|
||||
session.commit()
|
||||
|
||||
@@ -672,16 +672,14 @@ Nested Session Transactions with SAVEPOINT
|
||||
|
||||
Available at the Engine and ORM level. ORM docs so far:
|
||||
|
||||
http://www.sqlalchemy.org/docs/04/session.html#unitofwork_ma
|
||||
naging
|
||||
http://www.sqlalchemy.org/docs/04/session.html#unitofwork_managing
|
||||
|
||||
Two-Phase Commit Sessions
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Available at the Engine and ORM level. ORM docs so far:
|
||||
|
||||
http://www.sqlalchemy.org/docs/04/session.html#unitofwork_ma
|
||||
naging
|
||||
http://www.sqlalchemy.org/docs/04/session.html#unitofwork_managing
|
||||
|
||||
Inheritance
|
||||
-----------
|
||||
@@ -737,8 +735,8 @@ New Operator System
|
||||
|
||||
SQL operators and more or less every SQL keyword there is
|
||||
are now abstracted into the compiler layer. They now act
|
||||
intelligently and are type/backend aware, see: http://www.sq
|
||||
lalchemy.org/docs/04/sqlexpression.html#sql_operators
|
||||
intelligently and are type/backend aware, see:
|
||||
http://www.sqlalchemy.org/docs/04/sqlexpression.html#sql_operators
|
||||
|
||||
All ``type`` Keyword Arguments Renamed to ``type_``
|
||||
---------------------------------------------------
|
||||
|
||||
Vendored
+3
-3
@@ -72,7 +72,7 @@ Object Relational Mapping
|
||||
::
|
||||
|
||||
for row in session.query(User.name, func.count(Address.id).label('numaddresses')).join(Address).group_by(User.name):
|
||||
print "name", row.name, "number", row.numaddresses
|
||||
print("name", row.name, "number", row.numaddresses)
|
||||
|
||||
``Query`` has a ``statement`` accessor, as well as a
|
||||
``subquery()`` method which allow ``Query`` to be used to
|
||||
@@ -144,7 +144,7 @@ Object Relational Mapping
|
||||
::
|
||||
|
||||
for col in table.c:
|
||||
print col
|
||||
print(col)
|
||||
|
||||
Work with a specific column:
|
||||
|
||||
@@ -606,7 +606,7 @@ Removed
|
||||
|
||||
from sqlalchemy.orm import aliased
|
||||
address_alias = aliased(Address)
|
||||
print session.query(User, address_alias).join((address_alias, User.addresses)).all()
|
||||
print(session.query(User, address_alias).join((address_alias, User.addresses)).all())
|
||||
|
||||
* ``sqlalchemy.orm.Mapper``
|
||||
|
||||
|
||||
Vendored
+21
-21
@@ -1,6 +1,6 @@
|
||||
==============================
|
||||
=============================
|
||||
What's New in SQLAlchemy 0.6?
|
||||
==============================
|
||||
=============================
|
||||
|
||||
.. admonition:: About this Document
|
||||
|
||||
@@ -68,7 +68,7 @@ The URL format used by ``create_engine()`` has been enhanced
|
||||
to handle any number of DBAPIs for a particular backend,
|
||||
using a scheme that is inspired by that of JDBC. The
|
||||
previous format still works, and will select a "default"
|
||||
DBAPI implementation, such as the Postgresql URL below that
|
||||
DBAPI implementation, such as the PostgreSQL URL below that
|
||||
will use psycopg2:
|
||||
|
||||
::
|
||||
@@ -180,7 +180,7 @@ But what happens if we say this?
|
||||
::
|
||||
|
||||
>>> if column('foo') == 5:
|
||||
... print "yes"
|
||||
... print("yes")
|
||||
...
|
||||
|
||||
In previous versions of SQLAlchemy, the returned
|
||||
@@ -205,7 +205,7 @@ That means code such as the following:
|
||||
::
|
||||
|
||||
if expression:
|
||||
print "the expression is:", expression
|
||||
print("the expression is:", expression)
|
||||
|
||||
Would not evaluate if ``expression`` was a binary clause.
|
||||
Since the above pattern should never be used, the base
|
||||
@@ -227,7 +227,7 @@ Code that wants to check for the presence of a
|
||||
::
|
||||
|
||||
if expression is not None:
|
||||
print "the expression is:", expression
|
||||
print("the expression is:", expression)
|
||||
|
||||
Keep in mind, **this applies to Table and Column objects
|
||||
too**.
|
||||
@@ -306,7 +306,7 @@ A rule that was designed to help SQLite has been removed,
|
||||
that of the first compound element within another compound
|
||||
(such as, a ``union()`` inside of an ``except_()``) wouldn't
|
||||
be parenthesized. This is inconsistent and produces the
|
||||
wrong results on Postgresql, which has precedence rules
|
||||
wrong results on PostgreSQL, which has precedence rules
|
||||
regarding INTERSECTION, and its generally a surprise. When
|
||||
using complex composites with SQLite, you now need to turn
|
||||
the first element into a subquery (which is also compatible
|
||||
@@ -415,7 +415,7 @@ expression object:
|
||||
create = CreateTable(mytable)
|
||||
|
||||
# dumps the CREATE TABLE as a string
|
||||
print create
|
||||
print(create)
|
||||
|
||||
# executes the CREATE TABLE statement
|
||||
engine.execute(create)
|
||||
@@ -568,11 +568,11 @@ To use an inspector:
|
||||
from sqlalchemy.engine.reflection import Inspector
|
||||
insp = Inspector.from_engine(my_engine)
|
||||
|
||||
print insp.get_schema_names()
|
||||
print(insp.get_schema_names())
|
||||
|
||||
the ``from_engine()`` method will in some cases provide a
|
||||
backend-specific inspector with additional capabilities,
|
||||
such as that of Postgresql which provides a
|
||||
such as that of PostgreSQL which provides a
|
||||
``get_table_oid()`` method:
|
||||
|
||||
::
|
||||
@@ -581,14 +581,14 @@ such as that of Postgresql which provides a
|
||||
my_engine = create_engine('postgresql://...')
|
||||
pg_insp = Inspector.from_engine(my_engine)
|
||||
|
||||
print pg_insp.get_table_oid('my_table')
|
||||
print(pg_insp.get_table_oid('my_table'))
|
||||
|
||||
RETURNING Support
|
||||
=================
|
||||
|
||||
The ``insert()``, ``update()`` and ``delete()`` constructs
|
||||
now support a ``returning()`` method, which corresponds to
|
||||
the SQL RETURNING clause as supported by Postgresql, Oracle,
|
||||
the SQL RETURNING clause as supported by PostgreSQL, Oracle,
|
||||
MS-SQL, and Firebird. It is not supported for any other
|
||||
backend at this time.
|
||||
|
||||
@@ -603,7 +603,7 @@ columns will be returned as a regular result set:
|
||||
table.insert().values(data='some data').returning(table.c.id, table.c.timestamp)
|
||||
)
|
||||
row = result.first()
|
||||
print "ID:", row['id'], "Timestamp:", row['timestamp']
|
||||
print("ID:", row['id'], "Timestamp:", row['timestamp'])
|
||||
|
||||
The implementation of RETURNING across the four supported
|
||||
backends varies wildly, in the case of Oracle requiring an
|
||||
@@ -659,7 +659,7 @@ scenes to provide two goals:
|
||||
Highlights of these changes include:
|
||||
|
||||
* The construction of types within dialects has been totally
|
||||
overhauled. Dialects now define publically available types
|
||||
overhauled. Dialects now define publicly available types
|
||||
as UPPERCASE names exclusively, and internal
|
||||
implementation types using underscore identifiers (i.e.
|
||||
are private). The system by which types are expressed in
|
||||
@@ -747,7 +747,7 @@ Note that the ``assert_unicode`` flag is now deprecated.
|
||||
SQLAlchemy allows the DBAPI and backend database in use to
|
||||
handle Unicode parameters when available, and does not add
|
||||
operational overhead by checking the incoming type; modern
|
||||
systems like sqlite and Postgresql will raise an encoding
|
||||
systems like sqlite and PostgreSQL will raise an encoding
|
||||
error on their end if invalid data is passed. In those
|
||||
cases where SQLAlchemy does need to coerce a bind parameter
|
||||
from Python Unicode to an encoded string, or when the
|
||||
@@ -766,13 +766,13 @@ default, this type generates a ``VARCHAR`` using the size of
|
||||
the largest label, and applies a CHECK constraint to the
|
||||
table within the CREATE TABLE statement. When using MySQL,
|
||||
the type by default uses MySQL's ENUM type, and when using
|
||||
Postgresql the type will generate a user defined type using
|
||||
PostgreSQL the type will generate a user defined type using
|
||||
``CREATE TYPE <mytype> AS ENUM``. In order to create the
|
||||
type using Postgresql, the ``name`` parameter must be
|
||||
type using PostgreSQL, the ``name`` parameter must be
|
||||
specified to the constructor. The type also accepts a
|
||||
``native_enum=False`` option which will issue the
|
||||
VARCHAR/CHECK strategy for all databases. Note that
|
||||
Postgresql ENUM types currently don't work with pg8000 or
|
||||
PostgreSQL ENUM types currently don't work with pg8000 or
|
||||
zxjdbc.
|
||||
|
||||
Reflection Returns Dialect-Specific Types
|
||||
@@ -921,7 +921,7 @@ A new kind of eager loading is added called "subquery"
|
||||
loading. This is a load that emits a second SQL query
|
||||
immediately after the first which loads full collections for
|
||||
all the parents in the first query, joining upwards to the
|
||||
parent using INNER JOIN. Subquery loading is used simlarly
|
||||
parent using INNER JOIN. Subquery loading is used similarly
|
||||
to the current joined-eager loading, using the
|
||||
```subqueryload()```` and ````subqueryload_all()```` options
|
||||
as well as the ````lazy='subquery'```` setting on
|
||||
@@ -958,7 +958,7 @@ innerjoin=True on relation, joinedload
|
||||
|
||||
Joined-eagerly loaded scalars and collections can now be
|
||||
instructed to use INNER JOIN instead of OUTER JOIN. On
|
||||
Postgresql this is observed to provide a 300-600% speedup on
|
||||
PostgreSQL this is observed to provide a 300-600% speedup on
|
||||
some queries. Set this flag for any many-to-one which is
|
||||
on a NOT NULLable foreign key, and similarly for any
|
||||
collection where related items are guaranteed to exist.
|
||||
@@ -1049,7 +1049,7 @@ Mutable Primary Keys with Joined Table Inheritance
|
||||
|
||||
A joined table inheritance config where the child table has
|
||||
a PK that foreign keys to the parent PK can now be updated
|
||||
on a CASCADE-capable database like Postgresql.
|
||||
on a CASCADE-capable database like PostgreSQL.
|
||||
``mapper()`` now has an option ``passive_updates=True``
|
||||
which indicates this foreign key is updated automatically.
|
||||
If on a non-cascading database like SQLite or MySQL/MyISAM,
|
||||
|
||||
Vendored
+11
-11
@@ -1,6 +1,6 @@
|
||||
==============================
|
||||
=============================
|
||||
What's New in SQLAlchemy 0.7?
|
||||
==============================
|
||||
=============================
|
||||
|
||||
.. admonition:: About this Document
|
||||
|
||||
@@ -310,14 +310,14 @@ These are implemented as an extension to the ``asc()`` and
|
||||
|
||||
:ticket:`723`
|
||||
|
||||
select.distinct(), query.distinct() accepts \*args for Postgresql DISTINCT ON
|
||||
select.distinct(), query.distinct() accepts \*args for PostgreSQL DISTINCT ON
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
This was already available by passing a list of expressions
|
||||
to the ``distinct`` keyword argument of ``select()``, the
|
||||
``distinct()`` method of ``select()`` and ``Query`` now
|
||||
accept positional arguments which are rendered as DISTINCT
|
||||
ON when a Postgresql backend is used.
|
||||
ON when a PostgreSQL backend is used.
|
||||
|
||||
`distinct() <http://www.sqlalchemy.org/docs/07/core/expressi
|
||||
on_api.html#sqlalchemy.sql.expression.Select.distinct>`_
|
||||
@@ -367,9 +367,9 @@ A "window function" provides to a statement information
|
||||
about the result set as it's produced. This allows criteria
|
||||
against various things like "row number", "rank" and so
|
||||
forth. They are known to be supported at least by
|
||||
Postgresql, SQL Server and Oracle, possibly others.
|
||||
PostgreSQL, SQL Server and Oracle, possibly others.
|
||||
|
||||
The best introduction to window functions is on Postgresql's
|
||||
The best introduction to window functions is on PostgreSQL's
|
||||
site, where window functions have been supported since
|
||||
version 8.4:
|
||||
|
||||
@@ -398,7 +398,7 @@ tutorial:
|
||||
label('avg')
|
||||
])
|
||||
|
||||
print s
|
||||
print(s)
|
||||
|
||||
SQL:
|
||||
|
||||
@@ -425,7 +425,7 @@ The default isolation level is set using the
|
||||
``isolation_level`` argument to ``create_engine()``.
|
||||
|
||||
Transaction isolation support is currently only supported by
|
||||
the Postgresql and SQLite backends.
|
||||
the PostgreSQL and SQLite backends.
|
||||
|
||||
`execution_options() <http://www.sqlalchemy.org/docs/07/core
|
||||
/connections.html#sqlalchemy.engine.base.Connection.executio
|
||||
@@ -483,7 +483,7 @@ C Extensions Build by Default
|
||||
This is as of 0.7b4. The exts will build if cPython 2.xx
|
||||
is detected. If the build fails, such as on a windows
|
||||
install, that condition is caught and the non-C install
|
||||
proceeds. The C exts won't build if Python 3 or Pypy is
|
||||
proceeds. The C exts won't build if Python 3 or PyPy is
|
||||
used.
|
||||
|
||||
Query.count() simplified, should work virtually always
|
||||
@@ -749,7 +749,7 @@ MS-SQL - ``String``/``Unicode``/``VARCHAR``/``NVARCHAR``/``VARBINARY`` emit "max
|
||||
On the MS-SQL backend, the String/Unicode types, and their
|
||||
counterparts VARCHAR/ NVARCHAR, as well as VARBINARY
|
||||
(:ticket:`1833`) emit "max" as the length when no length is
|
||||
specified. This makes it more compatible with Postgresql's
|
||||
specified. This makes it more compatible with PostgreSQL's
|
||||
VARCHAR type which is similarly unbounded when no length
|
||||
specified. SQL Server defaults the length on these types
|
||||
to '1' when no length is specified.
|
||||
@@ -997,7 +997,7 @@ same manner as that of 0.5 and 0.6:
|
||||
|
||||
::
|
||||
|
||||
print s.query(Parent).with_polymorphic([Child]).filter(Child.id > 7)
|
||||
print(s.query(Parent).with_polymorphic([Child]).filter(Child.id > 7))
|
||||
|
||||
Which on both 0.6 and 0.7 renders:
|
||||
|
||||
|
||||
Vendored
+29
-27
@@ -1,6 +1,6 @@
|
||||
==============================
|
||||
=============================
|
||||
What's New in SQLAlchemy 0.8?
|
||||
==============================
|
||||
=============================
|
||||
|
||||
.. admonition:: About this Document
|
||||
|
||||
@@ -282,7 +282,7 @@ A walkthrough of some key capabilities follows::
|
||||
<Mapper at 0x101521950; User>
|
||||
|
||||
>>> # an expression
|
||||
>>> print b.expression
|
||||
>>> print(b.expression)
|
||||
"user".id = address.user_id
|
||||
|
||||
>>> # inspect works on instances
|
||||
@@ -432,7 +432,7 @@ with a declarative base class::
|
||||
|
||||
@event.listens_for("load", Base, propagate=True)
|
||||
def on_load(target, context):
|
||||
print "New instance loaded:", target
|
||||
print("New instance loaded:", target)
|
||||
|
||||
# on_load() will be applied to SomeClass
|
||||
class SomeClass(Base):
|
||||
@@ -526,8 +526,10 @@ the :class:`.Table` to which ``User`` is mapped.
|
||||
|
||||
:ticket:`2245`
|
||||
|
||||
.. _change_orm_2365:
|
||||
|
||||
Query.update() supports UPDATE..FROM
|
||||
-------------------------------------
|
||||
------------------------------------
|
||||
|
||||
The new UPDATE..FROM mechanics work in query.update().
|
||||
Below, we emit an UPDATE against ``SomeEntity``, adding
|
||||
@@ -576,9 +578,9 @@ that were not flushed in the current transaction.
|
||||
:ticket:`2452`
|
||||
|
||||
Caching Example now uses dogpile.cache
|
||||
---------------------------------------
|
||||
--------------------------------------
|
||||
|
||||
The caching example now uses `dogpile.cache <http://dogpilecache.readthedocs.org/>`_.
|
||||
The caching example now uses `dogpile.cache <https://dogpilecache.readthedocs.io/>`_.
|
||||
Dogpile.cache is a rewrite of the caching portion
|
||||
of Beaker, featuring vastly simpler and faster operation,
|
||||
as well as support for distributed locking.
|
||||
@@ -607,7 +609,7 @@ this change is needed as illustrated in the Beaker example::
|
||||
:ticket:`2589`
|
||||
|
||||
New Core Features
|
||||
==================
|
||||
=================
|
||||
|
||||
Fully extensible, type-level operator support in Core
|
||||
-----------------------------------------------------
|
||||
@@ -622,7 +624,7 @@ now, the only way operators could be flexibly redefined was
|
||||
in the ORM layer, using :func:`.column_property` given a
|
||||
``comparator_factory`` argument. Third party libraries
|
||||
like GeoAlchemy therefore were forced to be ORM-centric and
|
||||
rely upon an array of hacks to apply new opertions as well
|
||||
rely upon an array of hacks to apply new operations as well
|
||||
as to get them to propagate correctly.
|
||||
|
||||
The new operator system in Core adds the one hook that's
|
||||
@@ -665,12 +667,12 @@ The new type is usable like any other type:
|
||||
)
|
||||
|
||||
stmt = select([data.c.x.log(data.c.y)]).where(data.c.x.log(2) < value)
|
||||
print conn.execute(stmt).fetchall()
|
||||
print(conn.execute(stmt).fetchall())
|
||||
|
||||
|
||||
New features which have come from this immediately include
|
||||
support for Postgresql's HSTORE type, as well as new
|
||||
operations associated with Postgresql's ARRAY
|
||||
support for PostgreSQL's HSTORE type, as well as new
|
||||
operations associated with PostgreSQL's ARRAY
|
||||
type. It also paves the way for existing types to acquire
|
||||
lots more operators that are specific to those types, such
|
||||
as more string, integer and date operators.
|
||||
@@ -686,12 +688,12 @@ as more string, integer and date operators.
|
||||
.. _feature_2623:
|
||||
|
||||
Multiple-VALUES support for Insert
|
||||
-----------------------------------
|
||||
----------------------------------
|
||||
|
||||
The :meth:`.Insert.values` method now supports a list of dictionaries,
|
||||
which will render a multi-VALUES statement such as
|
||||
``VALUES (<row1>), (<row2>), ...``. This is only relevant to backends which
|
||||
support this syntax, including Postgresql, SQLite, and MySQL. It is
|
||||
support this syntax, including PostgreSQL, SQLite, and MySQL. It is
|
||||
not the same thing as the usual ``executemany()`` style of INSERT which
|
||||
remains unchanged::
|
||||
|
||||
@@ -708,7 +710,7 @@ remains unchanged::
|
||||
:ticket:`2623`
|
||||
|
||||
Type Expressions
|
||||
-----------------
|
||||
----------------
|
||||
|
||||
SQL expressions can now be associated with types. Historically,
|
||||
:class:`.TypeEngine` has always allowed Python-side functions which
|
||||
@@ -738,7 +740,7 @@ Above, the ``LowerString`` type defines a SQL expression that will be emitted
|
||||
whenever the ``test_table.c.data`` column is rendered in the columns
|
||||
clause of a SELECT statement::
|
||||
|
||||
>>> print select([test_table]).where(test_table.c.data == 'HI')
|
||||
>>> print(select([test_table]).where(test_table.c.data == 'HI'))
|
||||
SELECT lower(test_table.data) AS data
|
||||
FROM test_table
|
||||
WHERE test_table.data = lower(:data_1)
|
||||
@@ -753,7 +755,7 @@ to embed PostGIS expressions inline in SQL based on type rules.
|
||||
:ticket:`1534`
|
||||
|
||||
Core Inspection System
|
||||
-----------------------
|
||||
----------------------
|
||||
|
||||
The :func:`.inspect` function introduced in :ref:`feature_orminspection_08`
|
||||
also applies to the core. Applied to an :class:`.Engine` it produces
|
||||
@@ -764,7 +766,7 @@ an :class:`.Inspector` object::
|
||||
|
||||
engine = create_engine("postgresql://scott:tiger@localhost/test")
|
||||
insp = inspect(engine)
|
||||
print insp.get_table_names()
|
||||
print(insp.get_table_names())
|
||||
|
||||
It can also be applied to any :class:`.ClauseElement`, which returns
|
||||
the :class:`.ClauseElement` itself, such as :class:`.Table`, :class:`.Column`,
|
||||
@@ -804,10 +806,10 @@ against a particular target selectable::
|
||||
|
||||
:meth:`.Select.correlate_except`
|
||||
|
||||
Postgresql HSTORE type
|
||||
PostgreSQL HSTORE type
|
||||
----------------------
|
||||
|
||||
Support for Postgresql's ``HSTORE`` type is now available as
|
||||
Support for PostgreSQL's ``HSTORE`` type is now available as
|
||||
:class:`.postgresql.HSTORE`. This type makes great usage
|
||||
of the new operator system to provide a full range of operators
|
||||
for HSTORE types, including index access, concatenation,
|
||||
@@ -840,7 +842,7 @@ and containment methods such as
|
||||
|
||||
:ticket:`2606`
|
||||
|
||||
Enhanced Postgresql ARRAY type
|
||||
Enhanced PostgreSQL ARRAY type
|
||||
------------------------------
|
||||
|
||||
The :class:`.postgresql.ARRAY` type will accept an optional
|
||||
@@ -939,7 +941,7 @@ Huge thanks to Nate Dub for the sprinting on this at Pycon 2012.
|
||||
|
||||
:ticket:`2363`
|
||||
|
||||
"COLLATE" supported across all dialects; in particular MySQL, Postgresql, SQLite
|
||||
"COLLATE" supported across all dialects; in particular MySQL, PostgreSQL, SQLite
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
The "collate" keyword, long accepted by the MySQL dialect, is now established
|
||||
@@ -947,7 +949,7 @@ on all :class:`.String` types and will render on any backend, including
|
||||
when features such as :meth:`.MetaData.create_all` and :func:`.cast` is used::
|
||||
|
||||
>>> stmt = select([cast(sometable.c.somechar, String(20, collation='utf8'))])
|
||||
>>> print stmt
|
||||
>>> print(stmt)
|
||||
SELECT CAST(sometable.somechar AS VARCHAR(20) COLLATE "utf8") AS anon_1
|
||||
FROM sometable
|
||||
|
||||
@@ -1079,7 +1081,7 @@ The new behavior allows the following test case to work::
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
# note we're using Postgresql to ensure that referential integrity
|
||||
# note we're using PostgreSQL to ensure that referential integrity
|
||||
# is enforced, for demonstration purposes.
|
||||
e = create_engine("postgresql://scott:tiger@localhost/test", echo=True)
|
||||
|
||||
@@ -1208,7 +1210,7 @@ Within a SELECT, the correlation takes effect as expected::
|
||||
|
||||
s2 = select([t1, t2]).where(t1.c.x == t2.c.y).where(t1.c.x == s)
|
||||
|
||||
print (s2)
|
||||
print(s2)
|
||||
|
||||
SELECT t1.x, t2.y FROM t1, t2
|
||||
WHERE t1.x = t2.y AND t1.x =
|
||||
@@ -1231,7 +1233,7 @@ create_all() and drop_all() will now honor an empty list as such
|
||||
The methods :meth:`.MetaData.create_all` and :meth:`.MetaData.drop_all`
|
||||
will now accept a list of :class:`.Table` objects that is empty,
|
||||
and will not emit any CREATE or DROP statements. Previously,
|
||||
an empty list was interepreted the same as passing ``None``
|
||||
an empty list was interpreted the same as passing ``None``
|
||||
for a collection, and CREATE/DROP would be emitted for all
|
||||
items unconditionally.
|
||||
|
||||
@@ -1241,7 +1243,7 @@ the previous behavior.
|
||||
:ticket:`2664`
|
||||
|
||||
Repaired the Event Targeting of :class:`.InstrumentationEvents`
|
||||
----------------------------------------------------------------
|
||||
---------------------------------------------------------------
|
||||
|
||||
The :class:`.InstrumentationEvents` series of event targets have
|
||||
documented that the events will only be fired off according to
|
||||
|
||||
Vendored
+38
-32
@@ -391,7 +391,7 @@ This is a small change demonstrated as follows::
|
||||
# in 0.8, this would fail to load the unloaded state.
|
||||
assert attributes.get_history(a1, 'data') == ((), ['a1',], ())
|
||||
|
||||
# load_history() is now equiavlent to get_history() with
|
||||
# load_history() is now equivalent to get_history() with
|
||||
# passive=PASSIVE_OFF ^ INIT_OK
|
||||
assert inspect(a1).attrs.data.load_history() == ((), ['a1',], ())
|
||||
|
||||
@@ -522,7 +522,7 @@ The "password" portion of a ``create_engine()`` no longer considers the ``+`` si
|
||||
For whatever reason, the Python function ``unquote_plus()`` was applied to the
|
||||
"password" field of a URL, which is an incorrect application of the
|
||||
encoding rules described in `RFC 1738 <http://www.ietf.org/rfc/rfc1738.txt>`_
|
||||
in that it escaped spaces as plus signs. The stringiciation of a URL
|
||||
in that it escaped spaces as plus signs. The stringification of a URL
|
||||
now only encodes ":", "@", or "/" and nothing else, and is now applied to both the
|
||||
``username`` and ``password`` fields (previously it only applied to the
|
||||
password). On parsing, encoded characters are converted, but plus signs and
|
||||
@@ -550,7 +550,7 @@ The precedence rules for COLLATE have been changed
|
||||
|
||||
Previously, an expression like the following::
|
||||
|
||||
print (column('x') == 'somevalue').collate("en_EN")
|
||||
print((column('x') == 'somevalue').collate("en_EN"))
|
||||
|
||||
would produce an expression like this::
|
||||
|
||||
@@ -567,7 +567,7 @@ by that of most database documentation::
|
||||
The potentially backwards incompatible change arises if the :meth:`.collate`
|
||||
operator is being applied to the right-hand column, as follows::
|
||||
|
||||
print column('x') == literal('somevalue').collate("en_EN")
|
||||
print(column('x') == literal('somevalue').collate("en_EN"))
|
||||
|
||||
In 0.8, this produces::
|
||||
|
||||
@@ -584,11 +584,11 @@ The :meth:`.ColumnOperators.collate` operator now works more appropriately withi
|
||||
generated::
|
||||
|
||||
>>> # 0.8
|
||||
>>> print column('x').collate('en_EN').desc()
|
||||
>>> print(column('x').collate('en_EN').desc())
|
||||
(x COLLATE en_EN) DESC
|
||||
|
||||
>>> # 0.9
|
||||
>>> print column('x').collate('en_EN').desc()
|
||||
>>> print(column('x').collate('en_EN').desc())
|
||||
x COLLATE en_EN DESC
|
||||
|
||||
:ticket:`2879`
|
||||
@@ -597,7 +597,7 @@ generated::
|
||||
|
||||
.. _migration_2878:
|
||||
|
||||
Postgresql CREATE TYPE <x> AS ENUM now applies quoting to values
|
||||
PostgreSQL CREATE TYPE <x> AS ENUM now applies quoting to values
|
||||
----------------------------------------------------------------
|
||||
|
||||
The :class:`.postgresql.ENUM` type will now apply escaping to single quote
|
||||
@@ -606,7 +606,7 @@ signs within the enumerated values::
|
||||
>>> from sqlalchemy.dialects import postgresql
|
||||
>>> type = postgresql.ENUM('one', 'two', "three's", name="myenum")
|
||||
>>> from sqlalchemy.dialects.postgresql import base
|
||||
>>> print base.CreateEnumType(type).compile(dialect=postgresql.dialect())
|
||||
>>> print(base.CreateEnumType(type).compile(dialect=postgresql.dialect()))
|
||||
CREATE TYPE myenum AS ENUM ('one','two','three''s')
|
||||
|
||||
Existing workarounds which already escape single quote signs will need to be
|
||||
@@ -879,7 +879,7 @@ New FOR UPDATE support on ``select()``, ``Query()``
|
||||
|
||||
An attempt is made to simplify the specification of the ``FOR UPDATE``
|
||||
clause on ``SELECT`` statements made within Core and ORM, and support is added
|
||||
for the ``FOR UPDATE OF`` SQL supported by Postgresql and Oracle.
|
||||
for the ``FOR UPDATE OF`` SQL supported by PostgreSQL and Oracle.
|
||||
|
||||
Using the core :meth:`.GenerativeSelect.with_for_update`, options like ``FOR SHARE`` and
|
||||
``NOWAIT`` can be specified individually, rather than linking to arbitrary
|
||||
@@ -976,11 +976,11 @@ identifier, or alternatively fetch the version identifier
|
||||
from each row at the same time the INSERT or UPDATE is emitted. When using a
|
||||
server-generated version identifier, it is strongly
|
||||
recommended that this feature be used only on a backend with strong RETURNING
|
||||
support (Postgresql, SQL Server; Oracle also supports RETURNING but the cx_oracle
|
||||
support (PostgreSQL, SQL Server; Oracle also supports RETURNING but the cx_oracle
|
||||
driver has only limited support), else the additional SELECT statements will
|
||||
add significant performance
|
||||
overhead. The example provided at :ref:`server_side_version_counter` illustrates
|
||||
the usage of the Postgresql ``xmin`` system column in order to integrate it with
|
||||
the usage of the PostgreSQL ``xmin`` system column in order to integrate it with
|
||||
the ORM's versioning feature.
|
||||
|
||||
.. seealso::
|
||||
@@ -1033,10 +1033,10 @@ from a backref::
|
||||
:ticket:`1535`
|
||||
|
||||
|
||||
Postgresql JSON Type
|
||||
PostgreSQL JSON Type
|
||||
--------------------
|
||||
|
||||
The Postgresql dialect now features a :class:`.postgresql.JSON` type to
|
||||
The PostgreSQL dialect now features a :class:`.postgresql.JSON` type to
|
||||
complement the :class:`.postgresql.HSTORE` type.
|
||||
|
||||
.. seealso::
|
||||
@@ -1085,7 +1085,7 @@ classes, including relationships, based on a reflected schema::
|
||||
session.commit()
|
||||
|
||||
# collection-based relationships are by default named "<classname>_collection"
|
||||
print (u1.address_collection)
|
||||
print(u1.address_collection)
|
||||
|
||||
Beyond that, the :class:`.AutomapBase` class is a declarative base, and supports
|
||||
all the features that declarative does. The "automapping" feature can be used
|
||||
@@ -1095,7 +1095,7 @@ can be dropped in using callable functions.
|
||||
|
||||
It is hoped that the :class:`.AutomapBase` system provides a quick
|
||||
and modernized solution to the problem that the very famous
|
||||
`SQLSoup <https://sqlsoup.readthedocs.org/en/latest/>`_
|
||||
`SQLSoup <https://sqlsoup.readthedocs.io/en/latest/>`_
|
||||
also tries to solve, that of generating a quick and rudimentary object
|
||||
model from an existing database on the fly. By addressing the issue strictly
|
||||
at the mapper configuration level, and integrating fully with existing
|
||||
@@ -1125,7 +1125,7 @@ as INNER JOINs could always be flattened)::
|
||||
|
||||
SELECT a.*, b.*, c.* FROM a LEFT OUTER JOIN (b JOIN c ON b.id = c.id) ON a.id
|
||||
|
||||
This was due to the fact that SQLite, even today, cannot parse a statement of the above format::
|
||||
This was due to the fact that SQLite up until version **3.7.16** cannot parse a statement of the above format::
|
||||
|
||||
SQLite version 3.7.15.2 2013-01-09 11:53:05
|
||||
Enter ".help" for instructions
|
||||
@@ -1149,7 +1149,7 @@ but today it seems clear every database tested except SQLite now supports it
|
||||
(Oracle 8, a very old database, doesn't support the JOIN keyword at all,
|
||||
but SQLAlchemy has always had a simple rewriting scheme in place for Oracle's syntax).
|
||||
To make matters worse, SQLAlchemy's usual workaround of applying a
|
||||
SELECT often degrades performance on platforms like Postgresql and MySQL::
|
||||
SELECT often degrades performance on platforms like PostgreSQL and MySQL::
|
||||
|
||||
SELECT a.*, anon_1.* FROM a LEFT OUTER JOIN (
|
||||
SELECT b.id AS b_id, c.id AS c_id
|
||||
@@ -1248,10 +1248,16 @@ with the above queries rewritten as::
|
||||
JOIN item ON item.id = order_item_1.item_id AND item.type IN (?)
|
||||
) AS anon_1 ON "order".id = anon_1.order_item_1_order_id
|
||||
|
||||
.. note::
|
||||
|
||||
As of SQLAlchemy 1.1, the workarounds present in this feature for SQLite
|
||||
will automatically disable themselves when SQLite version **3.7.16**
|
||||
or greater is detected, as SQLite has repaired support for right-nested joins.
|
||||
|
||||
The :meth:`.Join.alias`, :func:`.aliased` and :func:`.with_polymorphic` functions now
|
||||
support a new argument, ``flat=True``, which is used to construct aliases of joined-table
|
||||
entities without embedding into a SELECT. This flag is not on by default, to help with
|
||||
backwards compatibility - but now a "polymorhpic" selectable can be joined as a target
|
||||
backwards compatibility - but now a "polymorphic" selectable can be joined as a target
|
||||
without any subqueries generated::
|
||||
|
||||
employee_alias = with_polymorphic(Person, [Engineer, Manager], flat=True)
|
||||
@@ -1329,7 +1335,7 @@ immediately within the flush process.
|
||||
|
||||
In 0.9, as a result of the version id enhancements, ``eager_defaults`` can now
|
||||
emit a RETURNING clause for these values, so on a backend with strong RETURNING
|
||||
support in particular Postgresql, the ORM can fetch newly generated default
|
||||
support in particular PostgreSQL, the ORM can fetch newly generated default
|
||||
and SQL expression values inline with the INSERT or UPDATE. ``eager_defaults``,
|
||||
when enabled, makes use of RETURNING automatically when the target backend
|
||||
and :class:`.Table` supports "implicit returning".
|
||||
@@ -1453,7 +1459,7 @@ The typing system now handles the task of rendering "literal bind" values
|
||||
|
||||
A new method is added to :class:`.TypeEngine` :meth:`.TypeEngine.literal_processor`
|
||||
as well as :meth:`.TypeDecorator.process_literal_param` for :class:`.TypeDecorator`
|
||||
which take on the task of rendering so-called "inline literal paramters" - parameters
|
||||
which take on the task of rendering so-called "inline literal parameters" - parameters
|
||||
that normally render as "bound" values, but are instead being rendered inline
|
||||
into the SQL statement due to the compiler configuration. This feature is used
|
||||
when generating DDL for constructs such as :class:`.CheckConstraint`, as well
|
||||
@@ -1496,7 +1502,7 @@ insensitive names).
|
||||
|
||||
The :class:`.quoted_name` object is used internally as needed; however if
|
||||
other keywords require fixed quoting preferences, the class is available
|
||||
publically.
|
||||
publicly.
|
||||
|
||||
:ticket:`2812`
|
||||
|
||||
@@ -1517,46 +1523,46 @@ Starting with a table such as this::
|
||||
t1 = Table('t', MetaData(), Column('x', Boolean()), Column('y', Integer))
|
||||
|
||||
A select construct will now render the boolean column as a binary expression
|
||||
on backends that don't feature ``true``/``false`` constant beahvior::
|
||||
on backends that don't feature ``true``/``false`` constant behavior::
|
||||
|
||||
>>> from sqlalchemy import select, and_, false, true
|
||||
>>> from sqlalchemy.dialects import mysql, postgresql
|
||||
|
||||
>>> print select([t1]).where(t1.c.x).compile(dialect=mysql.dialect())
|
||||
>>> print(select([t1]).where(t1.c.x).compile(dialect=mysql.dialect()))
|
||||
SELECT t.x, t.y FROM t WHERE t.x = 1
|
||||
|
||||
The :func:`.and_` and :func:`.or_` constructs will now exhibit quasi
|
||||
"short circuit" behavior, that is truncating a rendered expression, when a
|
||||
:func:`.true` or :func:`.false` constant is present::
|
||||
|
||||
>>> print select([t1]).where(and_(t1.c.y > 5, false())).compile(
|
||||
... dialect=postgresql.dialect())
|
||||
>>> print(select([t1]).where(and_(t1.c.y > 5, false())).compile(
|
||||
... dialect=postgresql.dialect()))
|
||||
SELECT t.x, t.y FROM t WHERE false
|
||||
|
||||
:func:`.true` can be used as the base to build up an expression::
|
||||
|
||||
>>> expr = true()
|
||||
>>> expr = expr & (t1.c.y > 5)
|
||||
>>> print select([t1]).where(expr)
|
||||
>>> print(select([t1]).where(expr))
|
||||
SELECT t.x, t.y FROM t WHERE t.y > :y_1
|
||||
|
||||
The boolean constants :func:`.true` and :func:`.false` themselves render as
|
||||
``0 = 1`` and ``1 = 1`` for a backend with no boolean constants::
|
||||
|
||||
>>> print select([t1]).where(and_(t1.c.y > 5, false())).compile(
|
||||
... dialect=mysql.dialect())
|
||||
>>> print(select([t1]).where(and_(t1.c.y > 5, false())).compile(
|
||||
... dialect=mysql.dialect()))
|
||||
SELECT t.x, t.y FROM t WHERE 0 = 1
|
||||
|
||||
Interpretation of ``None``, while not particularly valid SQL, is at least
|
||||
now consistent::
|
||||
|
||||
>>> print select([t1.c.x]).where(None)
|
||||
>>> print(select([t1.c.x]).where(None))
|
||||
SELECT t.x FROM t WHERE NULL
|
||||
|
||||
>>> print select([t1.c.x]).where(None).where(None)
|
||||
>>> print(select([t1.c.x]).where(None).where(None))
|
||||
SELECT t.x FROM t WHERE NULL AND NULL
|
||||
|
||||
>>> print select([t1.c.x]).where(and_(None, None))
|
||||
>>> print(select([t1.c.x]).where(and_(None, None)))
|
||||
SELECT t.x FROM t WHERE NULL AND NULL
|
||||
|
||||
:ticket:`2804`
|
||||
@@ -1580,7 +1586,7 @@ E.g. an example like::
|
||||
|
||||
stmt = select([expr]).order_by(expr)
|
||||
|
||||
print stmt
|
||||
print(stmt)
|
||||
|
||||
Prior to 0.9 would render as::
|
||||
|
||||
|
||||
Vendored
+60
-62
@@ -1,6 +1,6 @@
|
||||
==============================
|
||||
=============================
|
||||
What's New in SQLAlchemy 1.0?
|
||||
==============================
|
||||
=============================
|
||||
|
||||
.. admonition:: About this Document
|
||||
|
||||
@@ -41,7 +41,7 @@ to proceed at speeds that rival direct use of the Core.
|
||||
:ticket:`3100`
|
||||
|
||||
New Performance Example Suite
|
||||
------------------------------
|
||||
-----------------------------
|
||||
|
||||
Inspired by the benchmarking done for the :ref:`bulk_operations` feature
|
||||
as well as for the :ref:`faq_how_to_profile` section of the FAQ, a new
|
||||
@@ -64,7 +64,7 @@ straightforward construction an invocation of :class:`.Query` objects
|
||||
using caching, which upon successive calls features vastly reduced
|
||||
Python function call overhead (over 75%). By specifying a
|
||||
:class:`.Query` object as a series of lambdas which are only invoked
|
||||
once, a query as a pre-compiled unit begins to be feasable::
|
||||
once, a query as a pre-compiled unit begins to be feasible::
|
||||
|
||||
from sqlalchemy.ext import baked
|
||||
from sqlalchemy import bindparam
|
||||
@@ -94,7 +94,7 @@ once, a query as a pre-compiled unit begins to be feasable::
|
||||
.. _feature_3150:
|
||||
|
||||
Improvements to declarative mixins, ``@declared_attr`` and related features
|
||||
----------------------------------------------------------------------------
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
The declarative system in conjunction with :class:`.declared_attr` has been
|
||||
overhauled to support new capabilities.
|
||||
@@ -163,18 +163,16 @@ is affixed to the base class only, and just inherited from subclasses.
|
||||
With :attr:`.declared_attr.cascading`, individual behaviors can be
|
||||
applied::
|
||||
|
||||
class HasSomeAttribute(object):
|
||||
class HasIdMixin(object):
|
||||
@declared_attr.cascading
|
||||
def some_id(cls):
|
||||
def id(cls):
|
||||
if has_inherited_table(cls):
|
||||
return Column(ForeignKey('myclass.id'), primary_key=True)
|
||||
else:
|
||||
return Column(Integer, primary_key=True)
|
||||
|
||||
return Column('id', Integer, primary_key=True)
|
||||
|
||||
class MyClass(HasSomeAttribute, Base):
|
||||
""
|
||||
class MyClass(HasIdMixin, Base):
|
||||
__tablename__ = 'myclass'
|
||||
# ...
|
||||
|
||||
class MySubClass(MyClass):
|
||||
@@ -324,7 +322,7 @@ object totally smokes both namedtuple and KeyedTuple::
|
||||
.. _feature_slots:
|
||||
|
||||
Significant Improvements in Structural Memory Use
|
||||
--------------------------------------------------
|
||||
-------------------------------------------------
|
||||
|
||||
Structural memory use has been improved via much more significant use
|
||||
of ``__slots__`` for many internal objects. This optimization is
|
||||
@@ -355,7 +353,7 @@ well as weakrefs, within a basic import of "nova.db.sqlalchemy.models"::
|
||||
.. _feature_updatemany:
|
||||
|
||||
UPDATE statements are now batched with executemany() in a flush
|
||||
----------------------------------------------------------------
|
||||
---------------------------------------------------------------
|
||||
|
||||
UPDATE statements can now be batched within an ORM flush
|
||||
into more performant executemany() call, similarly to how INSERT
|
||||
@@ -420,7 +418,7 @@ of inheritance-oriented scenarios, including:
|
||||
.. _bug_3227:
|
||||
|
||||
Session.get_bind() will receive the Mapper in all relevant Query cases
|
||||
-----------------------------------------------------------------------
|
||||
----------------------------------------------------------------------
|
||||
|
||||
A series of issues were repaired where the :meth:`.Session.get_bind`
|
||||
would not receive the primary :class:`.Mapper` of the :class:`.Query`,
|
||||
@@ -479,7 +477,7 @@ of object that one would retrieve from the :attr:`.Mapper.all_orm_descriptors`
|
||||
collection. This includes :class:`.hybrid_property` and :func:`.association_proxy`.
|
||||
However, as these objects are class-bound descriptors, they must be accessed
|
||||
**separately** from the class to which they are attached in order to get
|
||||
at the attribute. Below this is illustared using the
|
||||
at the attribute. Below this is illustrated using the
|
||||
:attr:`.Mapper.all_orm_descriptors` namespace::
|
||||
|
||||
class SomeObject(Base):
|
||||
@@ -503,7 +501,7 @@ as remaining ORM constructs such as :func:`.orm.synonym`.
|
||||
.. _bug_3188:
|
||||
|
||||
ColumnProperty constructs work a lot better with aliases, order_by
|
||||
-------------------------------------------------------------------
|
||||
------------------------------------------------------------------
|
||||
|
||||
A variety of issues regarding :func:`.column_property` have been fixed,
|
||||
most specifically with regards to the :func:`.aliased` construct as well
|
||||
@@ -530,7 +528,7 @@ Given a mapping like the following::
|
||||
A simple scenario that included "A.b" twice would fail to render
|
||||
correctly::
|
||||
|
||||
print sess.query(A, a1).order_by(a1.b)
|
||||
print(sess.query(A, a1).order_by(a1.b))
|
||||
|
||||
This would order by the wrong column::
|
||||
|
||||
@@ -585,7 +583,7 @@ New Features and Improvements - Core
|
||||
.. _feature_3034:
|
||||
|
||||
Select/Query LIMIT / OFFSET may be specified as an arbitrary SQL expression
|
||||
----------------------------------------------------------------------------
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
The :meth:`.Select.limit` and :meth:`.Select.offset` methods now accept
|
||||
any SQL expression, in addition to integer values, as arguments. The ORM
|
||||
@@ -634,7 +632,7 @@ does not support ALTER, in the case that during a DROP, the given tables have
|
||||
an unresolvable cycle; in this case a warning is emitted, and the tables
|
||||
are dropped with **no** ordering, which is usually fine on SQLite unless
|
||||
constraints are enabled. To resolve the warning and proceed with at least
|
||||
a partial ordering on a SQLite database, particuarly one where constraints
|
||||
a partial ordering on a SQLite database, particularly one where constraints
|
||||
are enabled, re-apply "use_alter" flags to those
|
||||
:class:`.ForeignKey` and :class:`.ForeignKeyConstraint` objects which should
|
||||
be explicitly omitted from the sort.
|
||||
@@ -828,7 +826,7 @@ the :class:`.Constraint` is constructed::
|
||||
.. _feature_insert_from_select_defaults:
|
||||
|
||||
INSERT FROM SELECT now includes Python and SQL-expression defaults
|
||||
-------------------------------------------------------------------
|
||||
------------------------------------------------------------------
|
||||
|
||||
:meth:`.Insert.from_select` now includes Python and SQL-expression defaults if
|
||||
otherwise unspecified; the limitation where non-server column defaults
|
||||
@@ -845,7 +843,7 @@ expressions are rendered as constants into the SELECT statement::
|
||||
Column('y', Integer, default=func.somefunction()))
|
||||
|
||||
stmt = select([t.c.x])
|
||||
print t.insert().from_select(['x'], stmt)
|
||||
print(t.insert().from_select(['x'], stmt))
|
||||
|
||||
Will render::
|
||||
|
||||
@@ -898,12 +896,12 @@ UniqueConstraint is now part of the Table reflection process
|
||||
A :class:`.Table` object populated using ``autoload=True`` will now
|
||||
include :class:`.UniqueConstraint` constructs as well as
|
||||
:class:`.Index` constructs. This logic has a few caveats for
|
||||
Postgresql and Mysql:
|
||||
PostgreSQL and MySQL:
|
||||
|
||||
Postgresql
|
||||
PostgreSQL
|
||||
^^^^^^^^^^
|
||||
|
||||
Postgresql has the behavior such that when a UNIQUE constraint is
|
||||
PostgreSQL has the behavior such that when a UNIQUE constraint is
|
||||
created, it implicitly creates a UNIQUE INDEX corresponding to that
|
||||
constraint as well. The :meth:`.Inspector.get_indexes` and the
|
||||
:meth:`.Inspector.get_unique_constraints` methods will continue to
|
||||
@@ -1073,7 +1071,7 @@ it emits SQL resembling::
|
||||
(None,)
|
||||
|
||||
Note above, there is a comparison ``WHERE ? = address.user_id`` where the
|
||||
bound value ``?`` is receving ``None``, or ``NULL`` in SQL. **This will
|
||||
bound value ``?`` is receiving ``None``, or ``NULL`` in SQL. **This will
|
||||
always return False in SQL**. The comparison here would in theory
|
||||
generate SQL as follows::
|
||||
|
||||
@@ -1356,11 +1354,11 @@ joined loader options can still be used::
|
||||
.. _bug_3233:
|
||||
|
||||
Changes and fixes in handling of duplicate join targets
|
||||
--------------------------------------------------------
|
||||
-------------------------------------------------------
|
||||
|
||||
Changes here encompass bugs where an unexpected and inconsistent
|
||||
behavior would occur in some scenarios when joining to an entity
|
||||
twice, or to multple single-table entities against the same table,
|
||||
twice, or to multiple single-table entities against the same table,
|
||||
without using a relationship-based ON clause, as well as when joining
|
||||
multiple times to the same target relationship.
|
||||
|
||||
@@ -1384,7 +1382,7 @@ Starting with a mapping as::
|
||||
|
||||
A query that joins to ``A.bs`` twice::
|
||||
|
||||
print s.query(A).join(A.bs).join(A.bs)
|
||||
print(s.query(A).join(A.bs).join(A.bs))
|
||||
|
||||
Will render::
|
||||
|
||||
@@ -1407,7 +1405,7 @@ larger path will now emit a warning::
|
||||
The bigger change involves when joining to an entity without using a
|
||||
relationship-bound path. If we join to ``B`` twice::
|
||||
|
||||
print s.query(A).join(B, B.a_id == A.id).join(B, B.a_id == A.id)
|
||||
print(s.query(A).join(B, B.a_id == A.id).join(B, B.a_id == A.id))
|
||||
|
||||
In 0.9, this would render as follows::
|
||||
|
||||
@@ -1467,9 +1465,9 @@ a mapping as follows::
|
||||
|
||||
s = Session()
|
||||
|
||||
print s.query(ASub1).join(B, ASub1.b).join(ASub2, B.a)
|
||||
print(s.query(ASub1).join(B, ASub1.b).join(ASub2, B.a))
|
||||
|
||||
print s.query(ASub1).join(B, ASub1.b).join(ASub2, ASub2.id == B.a_id)
|
||||
print(s.query(ASub1).join(B, ASub1.b).join(ASub2, ASub2.id == B.a_id))
|
||||
|
||||
The two queries at the bottom are equivalent, and should both render
|
||||
the identical SQL::
|
||||
@@ -1499,7 +1497,7 @@ as all the subclasses normally refer to the same table::
|
||||
|
||||
asub2_alias = aliased(ASub2)
|
||||
|
||||
print s.query(ASub1).join(B, ASub1.b).join(asub2_alias, B.a.of_type(asub2_alias))
|
||||
print(s.query(ASub1).join(B, ASub1.b).join(asub2_alias, B.a.of_type(asub2_alias)))
|
||||
|
||||
:ticket:`3233`
|
||||
:ticket:`3367`
|
||||
@@ -1663,7 +1661,7 @@ joined eager loading is now dropped in this case::
|
||||
LIMIT :param_1
|
||||
|
||||
In the case that the LEFT OUTER JOIN returns more than one row, the ORM
|
||||
has always emitted a warning here and ignored addtional results for
|
||||
has always emitted a warning here and ignored additional results for
|
||||
``uselist=False``, so the results in that error situation should not change.
|
||||
|
||||
:ticket:`3249`
|
||||
@@ -1962,7 +1960,7 @@ The output does what we say, but again it warns us::
|
||||
The above behavior applies to all those places where we might want to refer
|
||||
to a so-called "label reference"; ORDER BY and GROUP BY, but also within an
|
||||
OVER clause as well as a DISTINCT ON clause that refers to columns (e.g. the
|
||||
Postgresql syntax).
|
||||
PostgreSQL syntax).
|
||||
|
||||
We can still specify any arbitrary expression for ORDER BY or others using
|
||||
:func:`.text`::
|
||||
@@ -1980,8 +1978,8 @@ be qualified with :func:`.text` or similar.
|
||||
|
||||
.. _bug_3288:
|
||||
|
||||
Python-side defaults invoked for each row invidually when using a multivalued insert
|
||||
------------------------------------------------------------------------------------
|
||||
Python-side defaults invoked for each row individually when using a multivalued insert
|
||||
--------------------------------------------------------------------------------------
|
||||
|
||||
Support for Python-side column defaults when using the multi-valued
|
||||
version of :meth:`.Insert.values` were essentially not implemented, and
|
||||
@@ -2091,7 +2089,7 @@ rows (e.g. only the first row of many).
|
||||
A similar change is also applied to an INSERT..VALUES
|
||||
with multiple parameter sets; implicit RETURNING will no longer emit
|
||||
for this statement either. As both of these constructs deal
|
||||
with varible numbers of rows, the
|
||||
with variable numbers of rows, the
|
||||
:attr:`.ResultProxy.inserted_primary_key` accessor does not
|
||||
apply. Previously, there was a documentation note that one
|
||||
may prefer ``inline=True`` with INSERT..FROM SELECT as some databases
|
||||
@@ -2157,7 +2155,7 @@ state.
|
||||
.. _feature_3084:
|
||||
|
||||
MetaData.sorted_tables accessor is "deterministic"
|
||||
-----------------------------------------------------
|
||||
--------------------------------------------------
|
||||
|
||||
The sorting of tables resulting from the :attr:`.MetaData.sorted_tables`
|
||||
accessor is "deterministic"; the ordering should be the same in all cases
|
||||
@@ -2211,7 +2209,7 @@ reflection from temp tables as well, which is :ticket:`3203`.
|
||||
|
||||
:ticket:`3204`
|
||||
|
||||
Dialect Improvements and Changes - Postgresql
|
||||
Dialect Improvements and Changes - PostgreSQL
|
||||
=============================================
|
||||
|
||||
.. _change_3319:
|
||||
@@ -2219,7 +2217,7 @@ Dialect Improvements and Changes - Postgresql
|
||||
Overhaul of ENUM type create/drop rules
|
||||
---------------------------------------
|
||||
|
||||
The rules for Postgresql :class:`.postgresql.ENUM` have been made more strict
|
||||
The rules for PostgreSQL :class:`.postgresql.ENUM` have been made more strict
|
||||
with regards to creating and dropping of the TYPE.
|
||||
|
||||
An :class:`.postgresql.ENUM` that is created **without** being explicitly
|
||||
@@ -2234,7 +2232,7 @@ corresponding to :meth:`.Table.create` and :meth:`.Table.drop`::
|
||||
table.drop(engine) # will emit DROP TABLE and DROP TYPE - new for 1.0
|
||||
|
||||
This means that if a second table also has an enum named 'myenum', the
|
||||
above DROP operation will now fail. In order to accomodate the use case
|
||||
above DROP operation will now fail. In order to accommodate the use case
|
||||
of a common shared enumerated type, the behavior of a metadata-associated
|
||||
enumeration has been enhanced.
|
||||
|
||||
@@ -2265,8 +2263,8 @@ flag::
|
||||
|
||||
:ticket:`3319`
|
||||
|
||||
New Postgresql Table options
|
||||
-----------------------------
|
||||
New PostgreSQL Table options
|
||||
----------------------------
|
||||
|
||||
Added support for PG table options TABLESPACE, ON COMMIT,
|
||||
WITH(OUT) OIDS, and INHERITS, when rendering DDL via
|
||||
@@ -2280,11 +2278,11 @@ the :class:`.Table` construct.
|
||||
|
||||
.. _feature_get_enums:
|
||||
|
||||
New get_enums() method with Postgresql Dialect
|
||||
New get_enums() method with PostgreSQL Dialect
|
||||
----------------------------------------------
|
||||
|
||||
The :func:`.inspect` method returns a :class:`.PGInspector` object in the
|
||||
case of Postgresql, which includes a new :meth:`.PGInspector.get_enums`
|
||||
case of PostgreSQL, which includes a new :meth:`.PGInspector.get_enums`
|
||||
method that returns information on all available ``ENUM`` types::
|
||||
|
||||
from sqlalchemy import inspect, create_engine
|
||||
@@ -2299,23 +2297,23 @@ method that returns information on all available ``ENUM`` types::
|
||||
|
||||
.. _feature_2891:
|
||||
|
||||
Postgresql Dialect reflects Materialized Views, Foreign Tables
|
||||
PostgreSQL Dialect reflects Materialized Views, Foreign Tables
|
||||
--------------------------------------------------------------
|
||||
|
||||
Changes are as follows:
|
||||
|
||||
* the :class:`Table` construct with ``autoload=True`` will now match a name
|
||||
that exists in the database as a materialized view or foriegn table.
|
||||
that exists in the database as a materialized view or foreign table.
|
||||
|
||||
* :meth:`.Inspector.get_view_names` will return plain and materialized view
|
||||
names.
|
||||
|
||||
* :meth:`.Inspector.get_table_names` does **not** change for Postgresql, it
|
||||
* :meth:`.Inspector.get_table_names` does **not** change for PostgreSQL, it
|
||||
continues to return only the names of plain tables.
|
||||
|
||||
* A new method :meth:`.PGInspector.get_foreign_table_names` is added which
|
||||
will return the names of tables that are specifically marked as "foreign"
|
||||
in the Postgresql schema tables.
|
||||
in the PostgreSQL schema tables.
|
||||
|
||||
The change to reflection involves adding ``'m'`` and ``'f'`` to the list
|
||||
of qualifiers we use when querying ``pg_class.relkind``, but this change
|
||||
@@ -2326,7 +2324,7 @@ running 0.9 in production.
|
||||
|
||||
.. _change_3264:
|
||||
|
||||
Postgresql ``has_table()`` now works for temporary tables
|
||||
PostgreSQL ``has_table()`` now works for temporary tables
|
||||
---------------------------------------------------------
|
||||
|
||||
This is a simple fix such that "has table" for temporary tables now works,
|
||||
@@ -2350,7 +2348,7 @@ so that code like the following may proceed::
|
||||
user_tmp.create(conn, checkfirst=True)
|
||||
|
||||
The very unlikely case that this behavior will cause a non-failing application
|
||||
to behave differently, is because Postgresql allows a non-temporary table
|
||||
to behave differently, is because PostgreSQL allows a non-temporary table
|
||||
to silently overwrite a temporary table. So code like the following will
|
||||
now act completely differently, no longer creating the real table following
|
||||
the temporary table::
|
||||
@@ -2384,11 +2382,11 @@ the temporary table::
|
||||
|
||||
.. _feature_gh134:
|
||||
|
||||
Postgresql FILTER keyword
|
||||
PostgreSQL FILTER keyword
|
||||
-------------------------
|
||||
|
||||
The SQL standard FILTER keyword for aggregate functions is now supported
|
||||
by Postgresql as of 9.4. SQLAlchemy allows this using
|
||||
by PostgreSQL as of 9.4. SQLAlchemy allows this using
|
||||
:meth:`.FunctionElement.filter`::
|
||||
|
||||
func.count(1).filter(True)
|
||||
@@ -2400,20 +2398,20 @@ by Postgresql as of 9.4. SQLAlchemy allows this using
|
||||
:class:`.FunctionFilter`
|
||||
|
||||
PG8000 dialect supports client side encoding
|
||||
---------------------------------------------
|
||||
--------------------------------------------
|
||||
|
||||
The :paramref:`.create_engine.encoding` parameter is now honored
|
||||
by the pg8000 dialect, using on connect handler which
|
||||
emits ``SET CLIENT_ENCODING`` matching the selected encoding.
|
||||
|
||||
PG8000 native JSONB support
|
||||
--------------------------------------
|
||||
---------------------------
|
||||
|
||||
Support for PG8000 versions greater than 1.10.1 has been added, where
|
||||
JSONB is supported natively.
|
||||
|
||||
|
||||
Support for psycopg2cffi Dialect on Pypy
|
||||
Support for psycopg2cffi Dialect on PyPy
|
||||
----------------------------------------
|
||||
|
||||
Support for the pypy psycopg2cffi dialect is added.
|
||||
@@ -2423,12 +2421,12 @@ Support for the pypy psycopg2cffi dialect is added.
|
||||
:mod:`sqlalchemy.dialects.postgresql.psycopg2cffi`
|
||||
|
||||
Dialect Improvements and Changes - MySQL
|
||||
=============================================
|
||||
========================================
|
||||
|
||||
.. _change_3155:
|
||||
|
||||
MySQL TIMESTAMP Type now renders NULL / NOT NULL in all cases
|
||||
--------------------------------------------------------------
|
||||
-------------------------------------------------------------
|
||||
|
||||
The MySQL dialect has always worked around MySQL's implicit NOT NULL
|
||||
default associated with TIMESTAMP columns by emitting NULL for
|
||||
@@ -2451,7 +2449,7 @@ columns.
|
||||
.. _change_3283:
|
||||
|
||||
MySQL SET Type Overhauled to support empty sets, unicode, blank value handling
|
||||
-------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
The :class:`.mysql.SET` type historically not included a system of handling
|
||||
blank sets and empty values separately; as different drivers had different
|
||||
@@ -2584,7 +2582,7 @@ and is generally in decent working order, if someone wants to pick up
|
||||
on polishing it.
|
||||
|
||||
Dialect Improvements and Changes - SQLite
|
||||
=============================================
|
||||
=========================================
|
||||
|
||||
SQLite named and unnamed UNIQUE and FOREIGN KEY constraints will inspect and reflect
|
||||
-------------------------------------------------------------------------------------
|
||||
@@ -2634,7 +2632,7 @@ to control the behavior completely, based on deprecation guidelines from
|
||||
Microsoft. See :ref:`mssql_large_type_deprecation` for details.
|
||||
|
||||
Dialect Improvements and Changes - Oracle
|
||||
=============================================
|
||||
=========================================
|
||||
|
||||
.. _change_3220:
|
||||
|
||||
@@ -2655,7 +2653,7 @@ CTE support has been fixed up for Oracle, and there is also a new feature
|
||||
:ticket:`3220`
|
||||
|
||||
New Oracle Keywords for DDL
|
||||
-----------------------------
|
||||
---------------------------
|
||||
|
||||
Keywords such as COMPRESS, ON COMMIT, BITMAP:
|
||||
|
||||
|
||||
Vendored
+2957
File diff suppressed because it is too large
Load Diff
Vendored
+1809
File diff suppressed because it is too large
Load Diff
Vendored
+1742
File diff suppressed because it is too large
Load Diff
+9
@@ -0,0 +1,9 @@
|
||||
.. change::
|
||||
:tags: bug, mysql
|
||||
:tickets: 4065
|
||||
:versions: 1.2.0b3, 1.1.14
|
||||
|
||||
mysqlclient as of 1.3.11 changed the exception
|
||||
class for a particular disconnect situation from
|
||||
InterfaceError to InternalError; the disconnection
|
||||
detection logic now accommodates this.
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
Individual per-changelog files go here
|
||||
in .rst format, which are pulled in by
|
||||
changelog (version 0.4.0 or higher) to
|
||||
be rendered into the changelog_xx.rst file.
|
||||
At release time, the files here are removed and written
|
||||
directly into the changelog.
|
||||
|
||||
Rationale is so that multiple changes being merged
|
||||
into gerrit don't produce conflicts. Note that
|
||||
gerrit does not support custom merge handlers unlike
|
||||
git itself.
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
Individual per-changelog files go here
|
||||
in .rst format, which are pulled in by
|
||||
changelog (version 0.4.0 or higher) to
|
||||
be rendered into the changelog_xx.rst file.
|
||||
At release time, the files here are removed and written
|
||||
directly into the changelog.
|
||||
|
||||
Rationale is so that multiple changes being merged
|
||||
into gerrit don't produce conflicts. Note that
|
||||
gerrit does not support custom merge handlers unlike
|
||||
git itself.
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
.. change::
|
||||
:tags: bug, engine
|
||||
:tickets: 4406
|
||||
|
||||
Comparing two objects of :class:`.URL` using ``__eq__()`` did not take port
|
||||
number into consideration, two objects differing only by port number were
|
||||
considered equal. Port comparison is now added in ``__eq__()`` method of
|
||||
:class:`.URL`, objects differing by port number are now not equal.
|
||||
Additionally, ``__ne__()`` was not implemented for :class:`.URL` which
|
||||
caused unexpected result when ``!=`` was used in Python2, since there are no
|
||||
implied relationships among the comparison operators in Python2.
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
.. change::
|
||||
:tags: bug, oracle
|
||||
:tickets: 4506
|
||||
|
||||
Added support for reflection of the :class:`.NCHAR` datatype to the Oracle
|
||||
dialect, and added :class:`.NCHAR` to the list of types exported by the
|
||||
Oracle dialect.
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
.. change::
|
||||
:tags: bug, orm
|
||||
:tickets: 4507
|
||||
|
||||
Fixed a regression in 1.2 due to the introduction of baked queries for
|
||||
relationship lazy loaders, where a race condition is created during the
|
||||
generation of the "lazy clause" which occurs within a memoized attribute. If
|
||||
two threads initialize the memoized attribute concurrently, the baked query
|
||||
could be generated with bind parameter keys that are then replaced with new
|
||||
keys by the next run, leading to a lazy load query that specifies the
|
||||
related criteria as ``None``. The fix establishes that the parameter names
|
||||
are fixed before the new clause and parameter objects are generated, so that
|
||||
the names are the same every time.
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
.. change::
|
||||
:tags: bug, examples
|
||||
:tickets: 4528
|
||||
|
||||
Fixed bug in large_resultsets example case where a re-named "id" variable
|
||||
due to code reformatting caused the test to fail. Pull request courtesy
|
||||
Matt Schuchhardt.
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
.. change::
|
||||
:tags: bug, mssql
|
||||
:tickets: 4536
|
||||
:versions: 1.3.1
|
||||
|
||||
A commit() is emitted after an isolation level change to SNAPSHOT, as both
|
||||
pyodbc and pymssql open an implicit transaction which blocks subsequent SQL
|
||||
from being emitted in the current transaction.
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
Individual per-changelog files go here
|
||||
in .rst format, which are pulled in by
|
||||
changelog (version 0.4.0 or higher) to
|
||||
be rendered into the changelog_xx.rst file.
|
||||
At release time, the files here are removed and written
|
||||
directly into the changelog.
|
||||
|
||||
Rationale is so that multiple changes being merged
|
||||
into gerrit don't produce conflicts. Note that
|
||||
gerrit does not support custom merge handlers unlike
|
||||
git itself.
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
.. change::
|
||||
:tags: bug, orm
|
||||
:tickets: 4537
|
||||
|
||||
Fixed bug where use of :func:`.with_polymorphic` or other aliased construct
|
||||
would not properly adapt when the aliased target were used as the
|
||||
:meth:`.Select.correlate_except` target of a subquery used inside of a
|
||||
:func:`.column_property`. This required a fix to the clause adaption
|
||||
mechanics to properly handle a selectable that shows up in the "correlate
|
||||
except" list, in a similar manner as which occurs for selectables that show
|
||||
up in the "correlate" list. This is ultimately a fairly fundamental bug
|
||||
that has lasted for a long time but it is hard to come across it.
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
.. change::
|
||||
:tags: bug, postgresql
|
||||
:tickets: 4550
|
||||
|
||||
Modified the :paramref:`.Select.with_for_update.of` parameter so that if a
|
||||
join or other composed selectable is passed, the individual :class:`.Table`
|
||||
objects will be filtered from it, allowing one to pass a join() object to
|
||||
the parameter, as occurs normally when using joined table inheritance with
|
||||
the ORM. Pull request courtesy Raymond Lu.
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
Individual per-changelog files go here
|
||||
in .rst format, which are pulled in by
|
||||
changelog (version 0.4.0 or higher) to
|
||||
be rendered into the changelog_xx.rst file.
|
||||
At release time, the files here are removed and written
|
||||
directly into the changelog.
|
||||
|
||||
Rationale is so that multiple changes being merged
|
||||
into gerrit don't produce conflicts. Note that
|
||||
gerrit does not support custom merge handlers unlike
|
||||
git itself.
|
||||
|
||||
Vendored
+21
-57
@@ -13,25 +13,6 @@
|
||||
|
||||
import sys
|
||||
import os
|
||||
import traceback
|
||||
|
||||
def force_install_reqs():
|
||||
import logging
|
||||
|
||||
log = logging.getLogger("pip")
|
||||
handler = logging.StreamHandler(sys.stderr)
|
||||
handler.setFormatter(logging.Formatter("[pip] %(message)s"))
|
||||
log.addHandler(handler)
|
||||
log.setLevel(logging.INFO)
|
||||
|
||||
log.info("READTHEDOCS is set, force-installing requirements.txt")
|
||||
|
||||
from pip.commands import install
|
||||
req = os.path.join(os.path.dirname(__file__), "requirements.txt")
|
||||
cmd = install.InstallCommand()
|
||||
options, args = cmd.parse_args(["-v", "-U", "-r", req])
|
||||
cmd.run(options, args)
|
||||
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
@@ -42,34 +23,20 @@ sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
import sqlalchemy
|
||||
|
||||
# attempt to force pip to definitely get the latest
|
||||
# versions of libraries, see
|
||||
# https://github.com/rtfd/readthedocs.org/issues/1293
|
||||
rtd = os.environ.get('READTHEDOCS', None) == 'True'
|
||||
if rtd:
|
||||
try:
|
||||
force_install_reqs()
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
needs_sphinx = '1.6.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.intersphinx',
|
||||
'zzzeeksphinx',
|
||||
'changelog',
|
||||
'sphinx_paramlinks',
|
||||
#'corrections'
|
||||
'zzzeeksphinx',
|
||||
'changelog',
|
||||
'sphinx_paramlinks',
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
@@ -96,13 +63,17 @@ changelog_inner_tag_sort = ["feature", "changed", "removed", "bug", "moved"]
|
||||
changelog_render_ticket = "http://www.sqlalchemy.org/trac/ticket/%s"
|
||||
|
||||
changelog_render_pullreq = {
|
||||
"bitbucket": "https://bitbucket.org/zzzeek/sqlalchemy/pull-request/%s",
|
||||
"default": "https://bitbucket.org/zzzeek/sqlalchemy/pull-request/%s",
|
||||
"github": "https://github.com/zzzeek/sqlalchemy/pull/%s",
|
||||
"default": "https://github.com/sqlalchemy/sqlalchemy/pull/%s",
|
||||
"github": "https://github.com/sqlalchemy/sqlalchemy/pull/%s",
|
||||
}
|
||||
|
||||
changelog_render_changeset = "http://www.sqlalchemy.org/trac/changeset/%s"
|
||||
|
||||
exclude_patterns = [
|
||||
'build',
|
||||
'**/unreleased*/*',
|
||||
]
|
||||
|
||||
autodocmods_convert_modname = {
|
||||
"sqlalchemy.sql.sqltypes": "sqlalchemy.types",
|
||||
"sqlalchemy.sql.type_api": "sqlalchemy.types",
|
||||
@@ -129,18 +100,18 @@ master_doc = 'contents'
|
||||
|
||||
# General information about the project.
|
||||
project = u'SQLAlchemy'
|
||||
copyright = u'2007-2015, the SQLAlchemy authors and contributors'
|
||||
copyright = u'2007-2019, the SQLAlchemy authors and contributors'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = "1.0"
|
||||
version = "1.3"
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = "1.0.8"
|
||||
release = "1.3.1"
|
||||
|
||||
release_date = "July 22, 2015"
|
||||
release_date = "March 9, 2019"
|
||||
|
||||
site_base = os.environ.get("RTD_SITE_BASE", "http://www.sqlalchemy.org")
|
||||
site_adapter_template = "docs_adapter.mako"
|
||||
@@ -148,7 +119,7 @@ site_adapter_py = "docs_adapter.py"
|
||||
|
||||
# arbitrary number recognized by builders.py, incrementing this
|
||||
# will force a rebuild
|
||||
build_number = 3
|
||||
build_number = "3"
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
@@ -160,10 +131,6 @@ build_number = 3
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||
#default_role = None
|
||||
|
||||
@@ -241,7 +208,9 @@ html_last_updated_fmt = '%m/%d/%Y %H:%M:%S'
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
html_additional_pages = {
|
||||
"notfound": "notfound.html"
|
||||
}
|
||||
|
||||
# If false, no module index is generated.
|
||||
html_domain_indices = False
|
||||
@@ -290,8 +259,8 @@ htmlhelp_basename = 'SQLAlchemydoc'
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('contents', 'sqlalchemy_%s.tex' % release.replace('.', '_'), ur'SQLAlchemy Documentation',
|
||||
ur'Mike Bayer', 'manual'),
|
||||
('contents', 'sqlalchemy_%s.tex' % release.replace('.', '_'), 'SQLAlchemy Documentation',
|
||||
'Mike Bayer', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
@@ -372,9 +341,4 @@ epub_copyright = u'2007-2015, SQLAlchemy authors'
|
||||
# Allow duplicate toc entries.
|
||||
#epub_tocdup = True
|
||||
|
||||
intersphinx_mapping = {
|
||||
'alembic': ('http://alembic.readthedocs.org/en/latest/', None),
|
||||
'psycopg2': ('http://pythonhosted.org/psycopg2', None),
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vendored
+1
@@ -15,6 +15,7 @@ documentation, see :ref:`index_toplevel`.
|
||||
core/index
|
||||
dialects/index
|
||||
faq/index
|
||||
errors
|
||||
changelog/index
|
||||
|
||||
Indices and tables
|
||||
|
||||
Vendored
+1
-1
@@ -6,7 +6,7 @@ Appendix: Copyright
|
||||
|
||||
This is the MIT license: `<http://www.opensource.org/licenses/mit-license.php>`_
|
||||
|
||||
Copyright (c) 2005-2015 Michael Bayer and contributors.
|
||||
Copyright (c) 2005-2019 Michael Bayer and contributors.
|
||||
SQLAlchemy is a trademark of Michael Bayer.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
|
||||
Vendored
+2
-2
@@ -1,6 +1,6 @@
|
||||
=================
|
||||
===============
|
||||
Core API Basics
|
||||
=================
|
||||
===============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
Vendored
+85
-14
@@ -1,8 +1,8 @@
|
||||
.. _connections_toplevel:
|
||||
|
||||
=====================================
|
||||
====================================
|
||||
Working with Engines and Connections
|
||||
=====================================
|
||||
====================================
|
||||
|
||||
.. module:: sqlalchemy.engine
|
||||
|
||||
@@ -48,7 +48,7 @@ way is first procure a connection resource, which you get via the
|
||||
connection = engine.connect()
|
||||
result = connection.execute("select username from users")
|
||||
for row in result:
|
||||
print "username:", row['username']
|
||||
print("username:", row['username'])
|
||||
connection.close()
|
||||
|
||||
The connection is an instance of :class:`.Connection`,
|
||||
@@ -76,7 +76,7 @@ The above procedure can be performed in a shorthand way by using the
|
||||
|
||||
result = engine.execute("select username from users")
|
||||
for row in result:
|
||||
print "username:", row['username']
|
||||
print("username:", row['username'])
|
||||
|
||||
Where above, the :meth:`~.Engine.execute` method acquires a new
|
||||
:class:`.Connection` on its own, executes the statement with that object,
|
||||
@@ -148,7 +148,7 @@ is available as well::
|
||||
.. _connections_nested_transactions:
|
||||
|
||||
Nesting of Transaction Blocks
|
||||
------------------------------
|
||||
-----------------------------
|
||||
|
||||
The :class:`.Transaction` object also handles "nested"
|
||||
behavior by keeping track of the outermost begin/commit pair. In this example,
|
||||
@@ -241,7 +241,7 @@ it so that a SELECT statement will issue a COMMIT::
|
||||
.. _dbengine_implicit:
|
||||
|
||||
Connectionless Execution, Implicit Execution
|
||||
=============================================
|
||||
============================================
|
||||
|
||||
Recall from the first section we mentioned executing with and without explicit
|
||||
usage of :class:`.Connection`. "Connectionless" execution
|
||||
@@ -251,7 +251,7 @@ of :class:`.Engine`::
|
||||
|
||||
result = engine.execute("select username from users")
|
||||
for row in result:
|
||||
print "username:", row['username']
|
||||
print("username:", row['username'])
|
||||
|
||||
In addition to "connectionless" execution, it is also possible
|
||||
to use the :meth:`~.Executable.execute` method of
|
||||
@@ -368,6 +368,69 @@ the SQL statement. When the :class:`.ResultProxy` is closed, the underlying
|
||||
:class:`.Connection` is closed for us, resulting in the
|
||||
DBAPI connection being returned to the pool with transactional resources removed.
|
||||
|
||||
.. _schema_translating:
|
||||
|
||||
Translation of Schema Names
|
||||
===========================
|
||||
|
||||
To support multi-tenancy applications that distribute common sets of tables
|
||||
into multiple schemas, the
|
||||
:paramref:`.Connection.execution_options.schema_translate_map`
|
||||
execution option may be used to repurpose a set of :class:`.Table` objects
|
||||
to render under different schema names without any changes.
|
||||
|
||||
Given a table::
|
||||
|
||||
user_table = Table(
|
||||
'user', metadata,
|
||||
Column('id', Integer, primary_key=True),
|
||||
Column('name', String(50))
|
||||
)
|
||||
|
||||
The "schema" of this :class:`.Table` as defined by the
|
||||
:paramref:`.Table.schema` attribute is ``None``. The
|
||||
:paramref:`.Connection.execution_options.schema_translate_map` can specify
|
||||
that all :class:`.Table` objects with a schema of ``None`` would instead
|
||||
render the schema as ``user_schema_one``::
|
||||
|
||||
connection = engine.connect().execution_options(
|
||||
schema_translate_map={None: "user_schema_one"})
|
||||
|
||||
result = connection.execute(user_table.select())
|
||||
|
||||
The above code will invoke SQL on the database of the form::
|
||||
|
||||
SELECT user_schema_one.user.id, user_schema_one.user.name FROM
|
||||
user_schema.user
|
||||
|
||||
That is, the schema name is substituted with our translated name. The
|
||||
map can specify any number of target->destination schemas::
|
||||
|
||||
connection = engine.connect().execution_options(
|
||||
schema_translate_map={
|
||||
None: "user_schema_one", # no schema name -> "user_schema_one"
|
||||
"special": "special_schema", # schema="special" becomes "special_schema"
|
||||
"public": None # Table objects with schema="public" will render with no schema
|
||||
})
|
||||
|
||||
The :paramref:`.Connection.execution_options.schema_translate_map` parameter
|
||||
affects all DDL and SQL constructs generated from the SQL expression language,
|
||||
as derived from the :class:`.Table` or :class:`.Sequence` objects.
|
||||
It does **not** impact literal string SQL used via the :func:`.expression.text`
|
||||
construct nor via plain strings passed to :meth:`.Connection.execute`.
|
||||
|
||||
The feature takes effect **only** in those cases where the name of the
|
||||
schema is derived directly from that of a :class:`.Table` or :class:`.Sequence`;
|
||||
it does not impact methods where a string schema name is passed directly.
|
||||
By this pattern, it takes effect within the "can create" / "can drop" checks
|
||||
performed by methods such as :meth:`.MetaData.create_all` or
|
||||
:meth:`.MetaData.drop_all` are called, and it takes effect when
|
||||
using table reflection given a :class:`.Table` object. However it does
|
||||
**not** affect the operations present on the :class:`.Inspector` object,
|
||||
as the schema name is passed to these methods explicitly.
|
||||
|
||||
.. versionadded:: 1.1
|
||||
|
||||
.. _engine_disposal:
|
||||
|
||||
Engine Disposal
|
||||
@@ -447,18 +510,24 @@ with the current thread, such that all parts of the
|
||||
application can participate in that transaction implicitly without the need to
|
||||
explicitly reference a :class:`.Connection`.
|
||||
|
||||
.. note::
|
||||
.. deprecated:: 1.3
|
||||
|
||||
The "threadlocal" feature is generally discouraged. It's
|
||||
designed for a particular pattern of usage which is generally
|
||||
considered as a legacy pattern. It has **no impact** on the "thread safety"
|
||||
of SQLAlchemy components
|
||||
or one's application. It also should not be used when using an ORM
|
||||
The "threadlocal" engine strategy is deprecated, and will be removed
|
||||
in a future release.
|
||||
|
||||
This strategy is designed for a particular pattern of usage which is
|
||||
generally considered as a legacy pattern. It has **no impact** on the
|
||||
"thread safety" of SQLAlchemy components or one's application. It also
|
||||
should not be used when using an ORM
|
||||
:class:`~sqlalchemy.orm.session.Session` object, as the
|
||||
:class:`~sqlalchemy.orm.session.Session` itself represents an ongoing
|
||||
transaction and itself handles the job of maintaining connection and
|
||||
transactional resources.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`change_4393_threadlocal`
|
||||
|
||||
Enabling ``threadlocal`` is achieved as follows::
|
||||
|
||||
db = create_engine('mysql://localhost/test', strategy='threadlocal')
|
||||
@@ -645,7 +714,6 @@ the need for separate installation. Use the ``register()`` function as follows
|
||||
The above will respond to ``create_engine("mysql+foodialect://")`` and load the
|
||||
``MyMySQLDialect`` class from the ``myapp.dialect`` module.
|
||||
|
||||
.. versionadded:: 0.8
|
||||
|
||||
Connection / Engine API
|
||||
=======================
|
||||
@@ -656,6 +724,9 @@ Connection / Engine API
|
||||
.. autoclass:: Connectable
|
||||
:members:
|
||||
|
||||
.. autoclass:: CreateEnginePlugin
|
||||
:members:
|
||||
|
||||
.. autoclass:: Engine
|
||||
:members:
|
||||
|
||||
|
||||
Vendored
+65
-32
@@ -3,9 +3,9 @@
|
||||
|
||||
.. module:: sqlalchemy.schema
|
||||
|
||||
=================================
|
||||
================================
|
||||
Defining Constraints and Indexes
|
||||
=================================
|
||||
================================
|
||||
|
||||
This section will discuss SQL :term:`constraints` and indexes. In SQLAlchemy
|
||||
the key classes include :class:`.ForeignKeyConstraint` and :class:`.Index`.
|
||||
@@ -145,7 +145,7 @@ most forms of ALTER. Given a schema like::
|
||||
)
|
||||
|
||||
When we call upon :meth:`.MetaData.create_all` on a backend such as the
|
||||
Postgresql backend, the cycle between these two tables is resolved and the
|
||||
PostgreSQL backend, the cycle between these two tables is resolved and the
|
||||
constraints are created separately:
|
||||
|
||||
.. sourcecode:: pycon+sql
|
||||
@@ -300,9 +300,8 @@ arguments. The value is any string which will be output after the appropriate
|
||||
)
|
||||
)
|
||||
|
||||
Note that these clauses are not supported on SQLite, and require ``InnoDB``
|
||||
tables when used with MySQL. They may also not be supported on other
|
||||
databases.
|
||||
Note that these clauses require ``InnoDB`` tables when used with MySQL.
|
||||
They may also not be supported on other databases.
|
||||
|
||||
|
||||
UNIQUE Constraint
|
||||
@@ -391,7 +390,7 @@ option of being configured directly::
|
||||
:class:`.PrimaryKeyConstraint` - detailed API documentation.
|
||||
|
||||
Setting up Constraints when using the Declarative ORM Extension
|
||||
----------------------------------------------------------------
|
||||
---------------------------------------------------------------
|
||||
|
||||
The :class:`.Table` is the SQLAlchemy Core construct that allows one to define
|
||||
table metadata, which among other things can be used by the SQLAlchemy ORM
|
||||
@@ -415,7 +414,7 @@ produced inline with the table definition, the database usually has a system
|
||||
in place in which names are automatically assigned to these constraints, if
|
||||
a name is not otherwise specified. When an existing database table is altered
|
||||
in a database using a command such as ``ALTER TABLE``, this command typically
|
||||
needs to specify expicit names for new constraints as well as be able to
|
||||
needs to specify explicit names for new constraints as well as be able to
|
||||
specify the name of an existing constraint that is to be dropped or modified.
|
||||
|
||||
Constraints can be named explicitly using the :paramref:`.Constraint.name` parameter,
|
||||
@@ -426,7 +425,7 @@ parameters which create :class:`.UniqueConstraint` and :class:`.Index` objects
|
||||
without an explicit name being specified.
|
||||
|
||||
The use case of alteration of existing tables and constraints can be handled
|
||||
by schema migration tools such as `Alembic <http://http://alembic.readthedocs.org/>`_.
|
||||
by schema migration tools such as `Alembic <https://alembic.sqlalchemy.org/>`_.
|
||||
However, neither Alembic nor SQLAlchemy currently create names for constraint
|
||||
objects where the name is otherwise unspecified, leading to the case where
|
||||
being able to alter existing constraints means that one must reverse-engineer
|
||||
@@ -507,14 +506,53 @@ object that is created using the :paramref:`.Column.index` parameter::
|
||||
>>> DEFAULT_NAMING_CONVENTION
|
||||
immutabledict({'ix': 'ix_%(column_0_label)s'})
|
||||
|
||||
The tokens available include ``%(table_name)s``,
|
||||
``%(referred_table_name)s``, ``%(column_0_name)s``, ``%(column_0_label)s``,
|
||||
``%(column_0_key)s``, ``%(referred_column_0_name)s``, and ``%(constraint_name)s``;
|
||||
the documentation for :paramref:`.MetaData.naming_convention` describes each
|
||||
individually. New tokens can also be added, by specifying an additional
|
||||
token and a callable within the naming_convention dictionary. For example,
|
||||
if we wanted to name our foreign key constraints using a GUID scheme,
|
||||
we could do that as follows::
|
||||
The tokens available include ``%(table_name)s``, ``%(referred_table_name)s``,
|
||||
``%(column_0_name)s``, ``%(column_0_label)s``, ``%(column_0_key)s``,
|
||||
``%(referred_column_0_name)s``, and ``%(constraint_name)s``, as well as
|
||||
multiple-column versions of each including ``%(column_0N_name)s``,
|
||||
``%(column_0_N_name)s``, ``%(referred_column_0_N_name)s`` which render all
|
||||
column names separated with or without an underscore. The documentation for
|
||||
:paramref:`.MetaData.naming_convention` has further detail on each of these
|
||||
conventions.
|
||||
|
||||
When a generated name, particularly those that use the multiple-column tokens,
|
||||
is too long for the identifier length limit of the target database
|
||||
(for example, PostgreSQL has a limit of 63 characters), the name will be
|
||||
deterministically truncated using a 4-character suffix based on the md5
|
||||
hash of the long name. For example, the naming convention below will
|
||||
generate very long names given the column names in use::
|
||||
|
||||
metadata = MetaData(naming_convention={
|
||||
"uq": "uq_%(table_name)s_%(column_0_N_name)s"
|
||||
})
|
||||
|
||||
long_names = Table(
|
||||
'long_names', metadata,
|
||||
Column('information_channel_code', Integer, key='a'),
|
||||
Column('billing_convention_name', Integer, key='b'),
|
||||
Column('product_identifier', Integer, key='c'),
|
||||
UniqueConstraint('a', 'b', 'c')
|
||||
)
|
||||
|
||||
On the PostgreSQL dialect, names longer than 63 characters will be truncated
|
||||
as in the following example::
|
||||
|
||||
CREATE TABLE long_names (
|
||||
information_channel_code INTEGER,
|
||||
billing_convention_name INTEGER,
|
||||
product_identifier INTEGER,
|
||||
CONSTRAINT uq_long_names_information_channel_code_billing_conventi_a79e
|
||||
UNIQUE (information_channel_code, billing_convention_name, product_identifier)
|
||||
)
|
||||
|
||||
The above suffix ``a79e`` is based on the md5 hash of the long name and will
|
||||
generate the same value every time to produce consistent names for a given
|
||||
schema.
|
||||
|
||||
New tokens can also be added, by specifying an additional token
|
||||
and a callable within the naming_convention dictionary. For example, if we
|
||||
wanted to name our foreign key constraints using a GUID scheme, we could do
|
||||
that as follows::
|
||||
|
||||
import uuid
|
||||
|
||||
@@ -561,14 +599,17 @@ name as follows::
|
||||
:paramref:`.MetaData.naming_convention` - for additional usage details
|
||||
as well as a listing of all available naming components.
|
||||
|
||||
:ref:`alembic:tutorial_constraint_names` - in the Alembic documentation.
|
||||
`The Importance of Naming Constraints <https://alembic.sqlalchemy.org/en/latest/naming.html>`_ - in the Alembic documentation.
|
||||
|
||||
.. versionadded:: 0.9.2 Added the :paramref:`.MetaData.naming_convention` argument.
|
||||
|
||||
.. versionadded:: 1.3.0 added multi-column naming tokens such as ``%(column_0_N_name)s``.
|
||||
Generated names that go beyond the character limit for the target database will be
|
||||
deterministically truncated.
|
||||
|
||||
.. _naming_check_constraints:
|
||||
|
||||
Naming CHECK Constraints
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The :class:`.CheckConstraint` object is configured against an arbitrary
|
||||
SQL expression, which can have any number of columns present, and additionally
|
||||
@@ -640,7 +681,7 @@ structure of the expression will determine which column is noted as
|
||||
.. _naming_schematypes:
|
||||
|
||||
Configuring Naming for Boolean, Enum, and other schema types
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The :class:`.SchemaType` class refers to type objects such as :class:`.Boolean`
|
||||
and :class:`.Enum` which generate a CHECK constraint accompanying the type.
|
||||
@@ -671,7 +712,7 @@ The above table will produce the constraint name ``ck_foo_flag_bool``::
|
||||
)
|
||||
|
||||
The :class:`.SchemaType` classes use special internal symbols so that
|
||||
the naming convention is only determined at DDL compile time. On Postgresql,
|
||||
the naming convention is only determined at DDL compile time. On PostgreSQL,
|
||||
there's a native BOOLEAN type, so the CHECK constraint of :class:`.Boolean`
|
||||
is not needed; we are safe to set up a :class:`.Boolean` type without a
|
||||
name, even though a naming convention is in place for check constraints.
|
||||
@@ -725,7 +766,6 @@ Constraints API
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
|
||||
.. autoclass:: PrimaryKeyConstraint
|
||||
:members:
|
||||
:inherited-members:
|
||||
@@ -814,10 +854,6 @@ identify columns::
|
||||
Index('idx_col34', 'col3', 'col4', unique=True)
|
||||
)
|
||||
|
||||
.. versionadded:: 0.7
|
||||
Support of "inline" definition inside the :class:`.Table`
|
||||
for :class:`.Index`\ .
|
||||
|
||||
The :class:`~sqlalchemy.schema.Index` object also supports its own ``create()`` method:
|
||||
|
||||
.. sourcecode:: python+sql
|
||||
@@ -829,7 +865,7 @@ The :class:`~sqlalchemy.schema.Index` object also supports its own ``create()``
|
||||
.. _schema_indexes_functional:
|
||||
|
||||
Functional Indexes
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:class:`.Index` supports SQL and function expressions, as supported by the
|
||||
target backend. To create an index against a column using a descending
|
||||
@@ -839,16 +875,13 @@ value, the :meth:`.ColumnElement.desc` modifier may be used::
|
||||
|
||||
Index('someindex', mytable.c.somecol.desc())
|
||||
|
||||
Or with a backend that supports functional indexes such as Postgresql,
|
||||
Or with a backend that supports functional indexes such as PostgreSQL,
|
||||
a "case insensitive" index can be created using the ``lower()`` function::
|
||||
|
||||
from sqlalchemy import func, Index
|
||||
|
||||
Index('someindex', func.lower(mytable.c.somecol))
|
||||
|
||||
.. versionadded:: 0.8 :class:`.Index` supports SQL expressions and functions
|
||||
as well as plain columns.
|
||||
|
||||
Index API
|
||||
---------
|
||||
|
||||
|
||||
Vendored
+128
-44
@@ -3,13 +3,13 @@
|
||||
.. _types_custom:
|
||||
|
||||
Custom Types
|
||||
------------
|
||||
============
|
||||
|
||||
A variety of methods exist to redefine the behavior of existing types
|
||||
as well as to provide new ones.
|
||||
|
||||
Overriding Type Compilation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
---------------------------
|
||||
|
||||
A frequent need is to force the "string" version of a type, that is
|
||||
the one rendered in a CREATE TABLE statement or other SQL function
|
||||
@@ -38,7 +38,7 @@ See the section :ref:`type_compilation_extension`, a subsection of
|
||||
.. _types_typedecorator:
|
||||
|
||||
Augmenting Existing Types
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
-------------------------
|
||||
|
||||
The :class:`.TypeDecorator` allows the creation of custom types which
|
||||
add bind-parameter and result-processing behavior to an existing
|
||||
@@ -59,7 +59,8 @@ to and from the database is required.
|
||||
|
||||
|
||||
TypeDecorator Recipes
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
---------------------
|
||||
|
||||
A few key :class:`.TypeDecorator` recipes follow.
|
||||
|
||||
.. _coerce_to_unicode:
|
||||
@@ -123,7 +124,7 @@ Backend-agnostic GUID Type
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Receives and returns Python uuid() objects. Uses the PG UUID type
|
||||
when using Postgresql, CHAR(32) on other backends, storing them
|
||||
when using PostgreSQL, CHAR(32) on other backends, storing them
|
||||
in stringified hex format. Can be modified to store
|
||||
binary in CHAR(16) if desired::
|
||||
|
||||
@@ -134,7 +135,7 @@ binary in CHAR(16) if desired::
|
||||
class GUID(TypeDecorator):
|
||||
"""Platform-independent GUID type.
|
||||
|
||||
Uses Postgresql's UUID type, otherwise uses
|
||||
Uses PostgreSQL's UUID type, otherwise uses
|
||||
CHAR(32), storing as stringified hex values.
|
||||
|
||||
"""
|
||||
@@ -153,19 +154,21 @@ binary in CHAR(16) if desired::
|
||||
return str(value)
|
||||
else:
|
||||
if not isinstance(value, uuid.UUID):
|
||||
return "%.32x" % uuid.UUID(value)
|
||||
return "%.32x" % uuid.UUID(value).int
|
||||
else:
|
||||
# hexstring
|
||||
return "%.32x" % value
|
||||
return "%.32x" % value.int
|
||||
|
||||
def process_result_value(self, value, dialect):
|
||||
if value is None:
|
||||
return value
|
||||
else:
|
||||
return uuid.UUID(value)
|
||||
if not isinstance(value, uuid.UUID):
|
||||
value = uuid.UUID(value)
|
||||
return value
|
||||
|
||||
Marshal JSON Strings
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This type uses ``simplejson`` to marshal Python data structures
|
||||
to/from JSON. Can be modified to use Python's builtin json encoder::
|
||||
@@ -195,19 +198,95 @@ to/from JSON. Can be modified to use Python's builtin json encoder::
|
||||
value = json.loads(value)
|
||||
return value
|
||||
|
||||
Note that the ORM by default will not detect "mutability" on such a type -
|
||||
Adding Mutability
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
The ORM by default will not detect "mutability" on such a type as above -
|
||||
meaning, in-place changes to values will not be detected and will not be
|
||||
flushed. Without further steps, you instead would need to replace the existing
|
||||
value with a new one on each parent object to detect changes. Note that
|
||||
there's nothing wrong with this, as many applications may not require that the
|
||||
values are ever mutated once created. For those which do have this requirement,
|
||||
support for mutability is best applied using the ``sqlalchemy.ext.mutable``
|
||||
extension - see the example in :ref:`mutable_toplevel`.
|
||||
flushed. Without further steps, you instead would need to replace the existing
|
||||
value with a new one on each parent object to detect changes::
|
||||
|
||||
obj.json_value["key"] = "value" # will *not* be detected by the ORM
|
||||
|
||||
obj.json_value = {"key": "value"} # *will* be detected by the ORM
|
||||
|
||||
The above limitation may be
|
||||
fine, as many applications may not require that the values are ever mutated
|
||||
once created. For those which do have this requirement, support for mutability
|
||||
is best applied using the ``sqlalchemy.ext.mutable`` extension. For a
|
||||
dictionary-oriented JSON structure, we can apply this as::
|
||||
|
||||
json_type = MutableDict.as_mutable(JSONEncodedDict)
|
||||
|
||||
class MyClass(Base):
|
||||
# ...
|
||||
|
||||
json_data = Column(json_type)
|
||||
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`mutable_toplevel`
|
||||
|
||||
Dealing with Comparison Operations
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The default behavior of :class:`.TypeDecorator` is to coerce the "right hand side"
|
||||
of any expression into the same type. For a type like JSON, this means that
|
||||
any operator used must make sense in terms of JSON. For some cases,
|
||||
users may wish for the type to behave like JSON in some circumstances, and
|
||||
as plain text in others. One example is if one wanted to handle the
|
||||
LIKE operator for the JSON type. LIKE makes no sense against a JSON structure,
|
||||
but it does make sense against the underlying textual representation. To
|
||||
get at this with a type like ``JSONEncodedDict``, we need to
|
||||
**coerce** the column to a textual form using :func:`.cast` or
|
||||
:func:`.type_coerce` before attempting to use this operator::
|
||||
|
||||
from sqlalchemy import type_coerce, String
|
||||
|
||||
stmt = select([my_table]).where(
|
||||
type_coerce(my_table.c.json_data, String).like('%foo%'))
|
||||
|
||||
:class:`.TypeDecorator` provides a built-in system for working up type
|
||||
translations like these based on operators. If we wanted to frequently use the
|
||||
LIKE operator with our JSON object interpreted as a string, we can build it
|
||||
into the type by overriding the :meth:`.TypeDecorator.coerce_compared_value`
|
||||
method::
|
||||
|
||||
from sqlalchemy.sql import operators
|
||||
from sqlalchemy import String
|
||||
|
||||
class JSONEncodedDict(TypeDecorator):
|
||||
|
||||
impl = VARCHAR
|
||||
|
||||
def coerce_compared_value(self, op, value):
|
||||
if op in (operators.like_op, operators.notlike_op):
|
||||
return String()
|
||||
else:
|
||||
return self
|
||||
|
||||
def process_bind_param(self, value, dialect):
|
||||
if value is not None:
|
||||
value = json.dumps(value)
|
||||
|
||||
return value
|
||||
|
||||
def process_result_value(self, value, dialect):
|
||||
if value is not None:
|
||||
value = json.loads(value)
|
||||
return value
|
||||
|
||||
Above is just one approach to handling an operator like "LIKE". Other
|
||||
applications may wish to raise ``NotImplementedError`` for operators that
|
||||
have no meaning with a JSON object such as "LIKE", rather than automatically
|
||||
coercing to text.
|
||||
|
||||
|
||||
.. _replacing_processors:
|
||||
|
||||
Replacing the Bind/Result Processing of Existing Types
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
------------------------------------------------------
|
||||
|
||||
Most augmentation of type behavior at the bind/result level
|
||||
is achieved using :class:`.TypeDecorator`. For the rare scenario
|
||||
@@ -245,13 +324,13 @@ cursor directly::
|
||||
return None
|
||||
return process
|
||||
|
||||
def adapt(self, impltype):
|
||||
def adapt(self, impltype, **kw):
|
||||
return MySpecialTime(self.special_argument)
|
||||
|
||||
.. _types_sql_value_processing:
|
||||
|
||||
Applying SQL-level Bind/Result Processing
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
-----------------------------------------
|
||||
|
||||
As seen in the sections :ref:`types_typedecorator` and :ref:`replacing_processors`,
|
||||
SQLAlchemy allows Python functions to be invoked both when parameters are sent
|
||||
@@ -261,7 +340,7 @@ possible to define SQL-level transformations as well. The rationale here is whe
|
||||
only the relational database contains a particular series of functions that are necessary
|
||||
to coerce incoming and outgoing data between an application and persistence format.
|
||||
Examples include using database-defined encryption/decryption functions, as well
|
||||
as stored procedures that handle geographic data. The Postgis extension to Postgresql
|
||||
as stored procedures that handle geographic data. The PostGIS extension to PostgreSQL
|
||||
includes an extensive array of SQL functions that are necessary for coercing
|
||||
data into particular formats.
|
||||
|
||||
@@ -271,7 +350,7 @@ can include implementations of
|
||||
when defined to return a non-``None`` value should return a :class:`.ColumnElement`
|
||||
expression to be injected into the SQL statement, either surrounding
|
||||
bound parameters or a column expression. For example, to build a ``Geometry``
|
||||
type which will apply the Postgis function ``ST_GeomFromText`` to all outgoing
|
||||
type which will apply the PostGIS function ``ST_GeomFromText`` to all outgoing
|
||||
values and the function ``ST_AsText`` to all incoming data, we can create
|
||||
our own subclass of :class:`.UserDefinedType` which provides these methods
|
||||
in conjunction with :data:`~.sqlalchemy.sql.expression.func`::
|
||||
@@ -297,8 +376,8 @@ and use it in a :func:`.select` construct::
|
||||
Column('geom_data', Geometry)
|
||||
)
|
||||
|
||||
print select([geometry]).where(
|
||||
geometry.c.geom_data == 'LINESTRING(189412 252431,189631 259122)')
|
||||
print(select([geometry]).where(
|
||||
geometry.c.geom_data == 'LINESTRING(189412 252431,189631 259122)'))
|
||||
|
||||
The resulting SQL embeds both functions as appropriate. ``ST_AsText``
|
||||
is applied to the columns clause so that the return value is run through
|
||||
@@ -315,7 +394,7 @@ with the labeling of the wrapped expression. Such as, if we rendered
|
||||
a :func:`.select` against a :func:`.label` of our expression, the string
|
||||
label is moved to the outside of the wrapped expression::
|
||||
|
||||
print select([geometry.c.geom_data.label('my_data')])
|
||||
print(select([geometry.c.geom_data.label('my_data')]))
|
||||
|
||||
Output::
|
||||
|
||||
@@ -324,7 +403,7 @@ Output::
|
||||
|
||||
For an example of subclassing a built in type directly, we subclass
|
||||
:class:`.postgresql.BYTEA` to provide a ``PGPString``, which will make use of the
|
||||
Postgresql ``pgcrypto`` extension to encrpyt/decrypt values
|
||||
PostgreSQL ``pgcrypto`` extension to encrypt/decrypt values
|
||||
transparently::
|
||||
|
||||
from sqlalchemy import create_engine, String, select, func, \
|
||||
@@ -361,10 +440,10 @@ transparently::
|
||||
conn.execute(message.insert(), username="some user",
|
||||
message="this is my message")
|
||||
|
||||
print conn.scalar(
|
||||
print(conn.scalar(
|
||||
select([message.c.message]).\
|
||||
where(message.c.username == "some user")
|
||||
)
|
||||
))
|
||||
|
||||
The ``pgp_sym_encrypt`` and ``pgp_sym_decrypt`` functions are applied
|
||||
to the INSERT and SELECT statements::
|
||||
@@ -380,17 +459,14 @@ to the INSERT and SELECT statements::
|
||||
{'pgp_sym_decrypt_1': 'this is my passphrase', 'username_1': 'some user'}
|
||||
|
||||
|
||||
.. versionadded:: 0.8 Added the :meth:`.TypeEngine.bind_expression` and
|
||||
:meth:`.TypeEngine.column_expression` methods.
|
||||
.. seealso::
|
||||
|
||||
See also:
|
||||
|
||||
:ref:`examples_postgis`
|
||||
:ref:`examples_postgis`
|
||||
|
||||
.. _types_operators:
|
||||
|
||||
Redefining and Creating New Operators
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
-------------------------------------
|
||||
|
||||
SQLAlchemy Core defines a fixed set of expression operators available to all column expressions.
|
||||
Some of these operations have the effect of overloading Python's built in operators;
|
||||
@@ -425,7 +501,7 @@ associated with the :class:`.Integer` type.
|
||||
Usage::
|
||||
|
||||
>>> sometable = Table("sometable", metadata, Column("data", MyInt))
|
||||
>>> print sometable.c.data + 5
|
||||
>>> print(sometable.c.data + 5)
|
||||
sometable.data goofy :data_1
|
||||
|
||||
The implementation for :meth:`.ColumnOperators.__add__` is consulted
|
||||
@@ -436,6 +512,15 @@ expression object produces a new SQL expression construct. Above, we
|
||||
could just as well have said ``self.expr.op("goofy")(other)`` instead
|
||||
of ``self.op("goofy")(other)``.
|
||||
|
||||
When using :meth:`.Operators.op` for comparison operations that return a
|
||||
boolean result, the :paramref:`.Operators.op.is_comparison` flag should be
|
||||
set to ``True``::
|
||||
|
||||
class MyInt(Integer):
|
||||
class comparator_factory(Integer.Comparator):
|
||||
def is_frobnozzled(self, other):
|
||||
return self.op("--is_frobnozzled->", is_comparison=True)(other)
|
||||
|
||||
New methods added to a :class:`.TypeEngine.Comparator` are exposed on an
|
||||
owning SQL expression
|
||||
using a ``__getattr__`` scheme, which exposes methods added to
|
||||
@@ -452,13 +537,12 @@ to integers::
|
||||
|
||||
Using the above type::
|
||||
|
||||
>>> print sometable.c.data.log(5)
|
||||
>>> print(sometable.c.data.log(5))
|
||||
log(:log_1, :log_2)
|
||||
|
||||
|
||||
Unary operations
|
||||
are also possible. For example, to add an implementation of the
|
||||
Postgresql factorial operator, we combine the :class:`.UnaryExpression` construct
|
||||
PostgreSQL factorial operator, we combine the :class:`.UnaryExpression` construct
|
||||
along with a :class:`.custom_op` to produce the factorial expression::
|
||||
|
||||
from sqlalchemy import Integer
|
||||
@@ -475,19 +559,19 @@ along with a :class:`.custom_op` to produce the factorial expression::
|
||||
Using the above type::
|
||||
|
||||
>>> from sqlalchemy.sql import column
|
||||
>>> print column('x', MyInteger).factorial()
|
||||
>>> print(column('x', MyInteger).factorial())
|
||||
x !
|
||||
|
||||
See also:
|
||||
.. seealso::
|
||||
|
||||
:attr:`.TypeEngine.comparator_factory`
|
||||
:meth:`.Operators.op`
|
||||
|
||||
:attr:`.TypeEngine.comparator_factory`
|
||||
|
||||
.. versionadded:: 0.8 The expression system was enhanced to support
|
||||
customization of operators on a per-type level.
|
||||
|
||||
|
||||
Creating New Types
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
------------------
|
||||
|
||||
The :class:`.UserDefinedType` class is provided as a simple base class
|
||||
for defining entirely new database types. Use this to represent native
|
||||
|
||||
Vendored
+142
-134
@@ -20,11 +20,120 @@ required, SQLAlchemy offers two techniques which can be used to add any DDL
|
||||
based on any condition, either accompanying the standard generation of tables
|
||||
or by itself.
|
||||
|
||||
Custom DDL
|
||||
----------
|
||||
|
||||
Custom DDL phrases are most easily achieved using the
|
||||
:class:`~sqlalchemy.schema.DDL` construct. This construct works like all the
|
||||
other DDL elements except it accepts a string which is the text to be emitted:
|
||||
|
||||
.. sourcecode:: python+sql
|
||||
|
||||
event.listen(
|
||||
metadata,
|
||||
"after_create",
|
||||
DDL("ALTER TABLE users ADD CONSTRAINT "
|
||||
"cst_user_name_length "
|
||||
" CHECK (length(user_name) >= 8)")
|
||||
)
|
||||
|
||||
A more comprehensive method of creating libraries of DDL constructs is to use
|
||||
custom compilation - see :ref:`sqlalchemy.ext.compiler_toplevel` for
|
||||
details.
|
||||
|
||||
|
||||
.. _schema_ddl_sequences:
|
||||
|
||||
Controlling DDL Sequences
|
||||
-------------------------
|
||||
|
||||
The :class:`~.schema.DDL` construct introduced previously also has the
|
||||
ability to be invoked conditionally based on inspection of the
|
||||
database. This feature is available using the :meth:`.DDLElement.execute_if`
|
||||
method. For example, if we wanted to create a trigger but only on
|
||||
the PostgreSQL backend, we could invoke this as::
|
||||
|
||||
mytable = Table(
|
||||
'mytable', metadata,
|
||||
Column('id', Integer, primary_key=True),
|
||||
Column('data', String(50))
|
||||
)
|
||||
|
||||
trigger = DDL(
|
||||
"CREATE TRIGGER dt_ins BEFORE INSERT ON mytable "
|
||||
"FOR EACH ROW BEGIN SET NEW.data='ins'; END"
|
||||
)
|
||||
|
||||
event.listen(
|
||||
mytable,
|
||||
'after_create',
|
||||
trigger.execute_if(dialect='postgresql')
|
||||
)
|
||||
|
||||
The :paramref:`.DDLElement.execute_if.dialect` keyword also accepts a tuple
|
||||
of string dialect names::
|
||||
|
||||
event.listen(
|
||||
mytable,
|
||||
"after_create",
|
||||
trigger.execute_if(dialect=('postgresql', 'mysql'))
|
||||
)
|
||||
event.listen(
|
||||
mytable,
|
||||
"before_drop",
|
||||
trigger.execute_if(dialect=('postgresql', 'mysql'))
|
||||
)
|
||||
|
||||
The :meth:`.DDLElement.execute_if` method can also work against a callable
|
||||
function that will receive the database connection in use. In the
|
||||
example below, we use this to conditionally create a CHECK constraint,
|
||||
first looking within the PostgreSQL catalogs to see if it exists:
|
||||
|
||||
.. sourcecode:: python+sql
|
||||
|
||||
def should_create(ddl, target, connection, **kw):
|
||||
row = connection.execute(
|
||||
"select conname from pg_constraint where conname='%s'" %
|
||||
ddl.element.name).scalar()
|
||||
return not bool(row)
|
||||
|
||||
def should_drop(ddl, target, connection, **kw):
|
||||
return not should_create(ddl, target, connection, **kw)
|
||||
|
||||
event.listen(
|
||||
users,
|
||||
"after_create",
|
||||
DDL(
|
||||
"ALTER TABLE users ADD CONSTRAINT "
|
||||
"cst_user_name_length CHECK (length(user_name) >= 8)"
|
||||
).execute_if(callable_=should_create)
|
||||
)
|
||||
event.listen(
|
||||
users,
|
||||
"before_drop",
|
||||
DDL(
|
||||
"ALTER TABLE users DROP CONSTRAINT cst_user_name_length"
|
||||
).execute_if(callable_=should_drop)
|
||||
)
|
||||
|
||||
{sql}users.create(engine)
|
||||
CREATE TABLE users (
|
||||
user_id SERIAL NOT NULL,
|
||||
user_name VARCHAR(40) NOT NULL,
|
||||
PRIMARY KEY (user_id)
|
||||
)
|
||||
|
||||
select conname from pg_constraint where conname='cst_user_name_length'
|
||||
ALTER TABLE users ADD CONSTRAINT cst_user_name_length CHECK (length(user_name) >= 8){stop}
|
||||
|
||||
{sql}users.drop(engine)
|
||||
select conname from pg_constraint where conname='cst_user_name_length'
|
||||
ALTER TABLE users DROP CONSTRAINT cst_user_name_length
|
||||
DROP TABLE users{stop}
|
||||
|
||||
Using the built-in DDLElement Classes
|
||||
-------------------------------------
|
||||
|
||||
The ``sqlalchemy.schema`` package contains SQL expression constructs that
|
||||
provide DDL expressions. For example, to produce a ``CREATE TABLE`` statement:
|
||||
|
||||
@@ -42,127 +151,39 @@ provide DDL expressions. For example, to produce a ``CREATE TABLE`` statement:
|
||||
){stop}
|
||||
|
||||
Above, the :class:`~sqlalchemy.schema.CreateTable` construct works like any
|
||||
other expression construct (such as ``select()``, ``table.insert()``, etc.). A
|
||||
full reference of available constructs is in :ref:`schema_api_ddl`.
|
||||
other expression construct (such as ``select()``, ``table.insert()``, etc.).
|
||||
All of SQLAlchemy's DDL oriented constructs are subclasses of
|
||||
the :class:`.DDLElement` base class; this is the base of all the
|
||||
objects corresponding to CREATE and DROP as well as ALTER,
|
||||
not only in SQLAlchemy but in Alembic Migrations as well.
|
||||
A full reference of available constructs is in :ref:`schema_api_ddl`.
|
||||
|
||||
The DDL constructs all extend a common base class which provides the
|
||||
capability to be associated with an individual
|
||||
:class:`~sqlalchemy.schema.Table` or :class:`~sqlalchemy.schema.MetaData`
|
||||
object, to be invoked upon create/drop events. Consider the example of a table
|
||||
which contains a CHECK constraint:
|
||||
User-defined DDL constructs may also be created as subclasses of
|
||||
:class:`.DDLElement` itself. The documentation in
|
||||
:ref:`sqlalchemy.ext.compiler_toplevel` has several examples of this.
|
||||
|
||||
.. sourcecode:: python+sql
|
||||
The event-driven DDL system described in the previous section
|
||||
:ref:`schema_ddl_sequences` is available with other :class:`.DDLElement`
|
||||
objects as well. However, when dealing with the built-in constructs
|
||||
such as :class:`.CreateIndex`, :class:`.CreateSequence`, etc, the event
|
||||
system is of **limited** use, as methods like :meth:`.Table.create` and
|
||||
:meth:`.MetaData.create_all` will invoke these constructs unconditionally.
|
||||
In a future SQLAlchemy release, the DDL event system including conditional
|
||||
execution will taken into account for built-in constructs that currently
|
||||
invoke in all cases.
|
||||
|
||||
users = Table('users', metadata,
|
||||
Column('user_id', Integer, primary_key=True),
|
||||
Column('user_name', String(40), nullable=False),
|
||||
CheckConstraint('length(user_name) >= 8',name="cst_user_name_length")
|
||||
)
|
||||
|
||||
{sql}users.create(engine)
|
||||
CREATE TABLE users (
|
||||
user_id SERIAL NOT NULL,
|
||||
user_name VARCHAR(40) NOT NULL,
|
||||
PRIMARY KEY (user_id),
|
||||
CONSTRAINT cst_user_name_length CHECK (length(user_name) >= 8)
|
||||
){stop}
|
||||
|
||||
The above table contains a column "user_name" which is subject to a CHECK
|
||||
constraint that validates that the length of the string is at least eight
|
||||
characters. When a ``create()`` is issued for this table, DDL for the
|
||||
:class:`~sqlalchemy.schema.CheckConstraint` will also be issued inline within
|
||||
the table definition.
|
||||
|
||||
The :class:`~sqlalchemy.schema.CheckConstraint` construct can also be
|
||||
constructed externally and associated with the
|
||||
:class:`~sqlalchemy.schema.Table` afterwards::
|
||||
|
||||
constraint = CheckConstraint('length(user_name) >= 8',name="cst_user_name_length")
|
||||
users.append_constraint(constraint)
|
||||
|
||||
So far, the effect is the same. However, if we create DDL elements
|
||||
corresponding to the creation and removal of this constraint, and associate
|
||||
them with the :class:`.Table` as events, these new events
|
||||
will take over the job of issuing DDL for the constraint. Additionally, the
|
||||
constraint will be added via ALTER:
|
||||
|
||||
.. sourcecode:: python+sql
|
||||
|
||||
from sqlalchemy import event
|
||||
|
||||
event.listen(
|
||||
users,
|
||||
"after_create",
|
||||
AddConstraint(constraint)
|
||||
)
|
||||
event.listen(
|
||||
users,
|
||||
"before_drop",
|
||||
DropConstraint(constraint)
|
||||
)
|
||||
|
||||
{sql}users.create(engine)
|
||||
CREATE TABLE users (
|
||||
user_id SERIAL NOT NULL,
|
||||
user_name VARCHAR(40) NOT NULL,
|
||||
PRIMARY KEY (user_id)
|
||||
)
|
||||
|
||||
ALTER TABLE users ADD CONSTRAINT cst_user_name_length CHECK (length(user_name) >= 8){stop}
|
||||
|
||||
{sql}users.drop(engine)
|
||||
ALTER TABLE users DROP CONSTRAINT cst_user_name_length
|
||||
DROP TABLE users{stop}
|
||||
|
||||
The real usefulness of the above becomes clearer once we illustrate the
|
||||
:meth:`.DDLElement.execute_if` method. This method returns a modified form of
|
||||
the DDL callable which will filter on criteria before responding to a
|
||||
received event. It accepts a parameter ``dialect``, which is the string
|
||||
name of a dialect or a tuple of such, which will limit the execution of the
|
||||
item to just those dialects. It also accepts a ``callable_`` parameter which
|
||||
may reference a Python callable which will be invoked upon event reception,
|
||||
returning ``True`` or ``False`` indicating if the event should proceed.
|
||||
|
||||
If our :class:`~sqlalchemy.schema.CheckConstraint` was only supported by
|
||||
Postgresql and not other databases, we could limit its usage to just that dialect::
|
||||
|
||||
event.listen(
|
||||
users,
|
||||
'after_create',
|
||||
AddConstraint(constraint).execute_if(dialect='postgresql')
|
||||
)
|
||||
event.listen(
|
||||
users,
|
||||
'before_drop',
|
||||
DropConstraint(constraint).execute_if(dialect='postgresql')
|
||||
)
|
||||
|
||||
Or to any set of dialects::
|
||||
|
||||
event.listen(
|
||||
users,
|
||||
"after_create",
|
||||
AddConstraint(constraint).execute_if(dialect=('postgresql', 'mysql'))
|
||||
)
|
||||
event.listen(
|
||||
users,
|
||||
"before_drop",
|
||||
DropConstraint(constraint).execute_if(dialect=('postgresql', 'mysql'))
|
||||
)
|
||||
|
||||
When using a callable, the callable is passed the ddl element, the
|
||||
:class:`.Table` or :class:`.MetaData`
|
||||
object whose "create" or "drop" event is in progress, and the
|
||||
:class:`.Connection` object being used for the
|
||||
operation, as well as additional information as keyword arguments. The
|
||||
callable can perform checks, such as whether or not a given item already
|
||||
exists. Below we define ``should_create()`` and ``should_drop()`` callables
|
||||
that check for the presence of our named constraint:
|
||||
We can illustrate an event-driven
|
||||
example with the :class:`.AddConstraint` and :class:`.DropConstraint`
|
||||
constructs, as the event-driven system will work for CHECK and UNIQUE
|
||||
constraints, using these as we did in our previous example of
|
||||
:meth:`.DDLElement.execute_if`:
|
||||
|
||||
.. sourcecode:: python+sql
|
||||
|
||||
def should_create(ddl, target, connection, **kw):
|
||||
row = connection.execute("select conname from pg_constraint where conname='%s'" % ddl.element.name).scalar()
|
||||
row = connection.execute(
|
||||
"select conname from pg_constraint where conname='%s'" %
|
||||
ddl.element.name).scalar()
|
||||
return not bool(row)
|
||||
|
||||
def should_drop(ddl, target, connection, **kw):
|
||||
@@ -194,26 +215,12 @@ that check for the presence of our named constraint:
|
||||
ALTER TABLE users DROP CONSTRAINT cst_user_name_length
|
||||
DROP TABLE users{stop}
|
||||
|
||||
Custom DDL
|
||||
----------
|
||||
|
||||
Custom DDL phrases are most easily achieved using the
|
||||
:class:`~sqlalchemy.schema.DDL` construct. This construct works like all the
|
||||
other DDL elements except it accepts a string which is the text to be emitted:
|
||||
|
||||
.. sourcecode:: python+sql
|
||||
|
||||
event.listen(
|
||||
metadata,
|
||||
"after_create",
|
||||
DDL("ALTER TABLE users ADD CONSTRAINT "
|
||||
"cst_user_name_length "
|
||||
" CHECK (length(user_name) >= 8)")
|
||||
)
|
||||
|
||||
A more comprehensive method of creating libraries of DDL constructs is to use
|
||||
custom compilation - see :ref:`sqlalchemy.ext.compiler_toplevel` for
|
||||
details.
|
||||
While the above example is against the built-in :class:`.AddConstraint`
|
||||
and :class:`.DropConstraint` objects, the main usefulness of DDL events
|
||||
for now remains focused on the use of the :class:`.DDL` construct itself,
|
||||
as well as with user-defined subclasses of :class:`.DDLElement` that aren't
|
||||
already part of the :meth:`.MetaData.create_all`, :meth:`.Table.create`,
|
||||
and corresponding "drop" processes.
|
||||
|
||||
.. _schema_api_ddl:
|
||||
|
||||
@@ -233,6 +240,7 @@ DDL Expression Constructs API
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
.. autoclass:: _CreateDropBase
|
||||
|
||||
.. autoclass:: CreateTable
|
||||
:members:
|
||||
|
||||
Vendored
+298
-160
@@ -5,7 +5,7 @@
|
||||
.. _metadata_defaults:
|
||||
|
||||
Column Insert/Update Defaults
|
||||
==============================
|
||||
=============================
|
||||
|
||||
SQLAlchemy provides a very rich featureset regarding column level events which
|
||||
take place during INSERT and UPDATE statements. Options include:
|
||||
@@ -45,7 +45,7 @@ defaults)::
|
||||
Python-Executed Functions
|
||||
-------------------------
|
||||
|
||||
The ``default`` and ``onupdate`` keyword arguments also accept Python
|
||||
The :paramref:`.Column.default` and :paramref:`.Column.onupdate` keyword arguments also accept Python
|
||||
functions. These functions are invoked at the time of insert or update if no
|
||||
other value for that column is supplied, and the value returned is used for
|
||||
the column's value. Below illustrates a crude "sequence" that assigns an
|
||||
@@ -67,12 +67,12 @@ built-in capabilities of the database should normally be used, which may
|
||||
include sequence objects or other autoincrementing capabilities. For primary
|
||||
key columns, SQLAlchemy will in most cases use these capabilities
|
||||
automatically. See the API documentation for
|
||||
:class:`~sqlalchemy.schema.Column` including the ``autoincrement`` flag, as
|
||||
:class:`~sqlalchemy.schema.Column` including the :paramref:`.Column.autoincrement` flag, as
|
||||
well as the section on :class:`~sqlalchemy.schema.Sequence` later in this
|
||||
chapter for background on standard primary key generation techniques.
|
||||
|
||||
To illustrate onupdate, we assign the Python ``datetime`` function ``now`` to
|
||||
the ``onupdate`` attribute::
|
||||
the :paramref:`.Column.onupdate` attribute::
|
||||
|
||||
import datetime
|
||||
|
||||
@@ -90,44 +90,64 @@ as the function itself without calling it (i.e. there are no parenthesis
|
||||
following) - SQLAlchemy will execute the function at the time the statement
|
||||
executes.
|
||||
|
||||
.. _context_default_functions:
|
||||
|
||||
Context-Sensitive Default Functions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The Python functions used by ``default`` and ``onupdate`` may also make use of
|
||||
the current statement's context in order to determine a value. The `context`
|
||||
of a statement is an internal SQLAlchemy object which contains all information
|
||||
about the statement being executed, including its source expression, the
|
||||
parameters associated with it and the cursor. The typical use case for this
|
||||
context with regards to default generation is to have access to the other
|
||||
values being inserted or updated on the row. To access the context, provide a
|
||||
function that accepts a single ``context`` argument::
|
||||
The Python functions used by :paramref:`.Column.default` and
|
||||
:paramref:`.Column.onupdate` may also make use of the current statement's
|
||||
context in order to determine a value. The `context` of a statement is an
|
||||
internal SQLAlchemy object which contains all information about the statement
|
||||
being executed, including its source expression, the parameters associated with
|
||||
it and the cursor. The typical use case for this context with regards to
|
||||
default generation is to have access to the other values being inserted or
|
||||
updated on the row. To access the context, provide a function that accepts a
|
||||
single ``context`` argument::
|
||||
|
||||
def mydefault(context):
|
||||
return context.current_parameters['counter'] + 12
|
||||
return context.get_current_parameters()['counter'] + 12
|
||||
|
||||
t = Table('mytable', meta,
|
||||
Column('counter', Integer),
|
||||
Column('counter_plus_twelve', Integer, default=mydefault, onupdate=mydefault)
|
||||
)
|
||||
|
||||
Above we illustrate a default function which will execute for all INSERT and
|
||||
UPDATE statements where a value for ``counter_plus_twelve`` was otherwise not
|
||||
provided, and the value will be that of whatever value is present in the
|
||||
execution for the ``counter`` column, plus the number 12.
|
||||
The above default generation function is applied so that it will execute for
|
||||
all INSERT and UPDATE statements where a value for ``counter_plus_twelve`` was
|
||||
otherwise not provided, and the value will be that of whatever value is present
|
||||
in the execution for the ``counter`` column, plus the number 12.
|
||||
|
||||
While the context object passed to the default function has many attributes,
|
||||
the ``current_parameters`` member is a special member provided only during the
|
||||
execution of a default function for the purposes of deriving defaults from its
|
||||
existing values. For a single statement that is executing many sets of bind
|
||||
parameters, the user-defined function is called for each set of parameters,
|
||||
and ``current_parameters`` will be provided with each individual parameter set
|
||||
for each execution.
|
||||
For a single statement that is being executed using "executemany" style, e.g.
|
||||
with multiple parameter sets passed to :meth:`.Connection.execute`, the user-
|
||||
defined function is called once for each set of parameters. For the use case of
|
||||
a multi-valued :class:`.Insert` construct (e.g. with more than one VALUES
|
||||
clause set up via the :meth:`.Insert.values` method), the user-defined function
|
||||
is also called once for each set of parameters.
|
||||
|
||||
SQL Expressions
|
||||
---------------
|
||||
When the function is invoked, the special method
|
||||
:meth:`.DefaultExecutionContext.get_current_parameters` is available from
|
||||
the context object (an subclass of :class:`.DefaultExecutionContext`). This
|
||||
method returns a dictionary of column-key to values that represents the
|
||||
full set of values for the INSERT or UPDATE statement. In the case of a
|
||||
multi-valued INSERT construct, the subset of parameters that corresponds to
|
||||
the individual VALUES clause is isolated from the full parameter dictionary
|
||||
and returned alone.
|
||||
|
||||
The "default" and "onupdate" keywords may also be passed SQL expressions,
|
||||
including select statements or direct function calls::
|
||||
.. versionadded:: 1.2
|
||||
|
||||
Added :meth:`.DefaultExecutionContext.get_current_parameters` method,
|
||||
which improves upon the still-present
|
||||
:attr:`.DefaultExecutionContext.current_parameters` attribute
|
||||
by offering the service of organizing multiple VALUES clauses
|
||||
into individual parameter dictionaries.
|
||||
|
||||
Client-Invoked SQL Expressions
|
||||
------------------------------
|
||||
|
||||
The :paramref:`.Column.default` and :paramref:`.Column.onupdate` keywords may
|
||||
also be passed SQL expressions, which are in most cases rendered inline within the
|
||||
INSERT or UPDATE statement::
|
||||
|
||||
t = Table("mytable", meta,
|
||||
Column('id', Integer, primary_key=True),
|
||||
@@ -136,7 +156,7 @@ including select statements or direct function calls::
|
||||
Column('create_date', DateTime, default=func.now()),
|
||||
|
||||
# define 'key' to pull its default from the 'keyvalues' table
|
||||
Column('key', String(20), default=keyvalues.select(keyvalues.c.type='type1', limit=1)),
|
||||
Column('key', String(20), default=select([keyvalues.c.key]).where(keyvalues.c.type='type1')),
|
||||
|
||||
# define 'last_modified' to use the current_timestamp SQL function on update
|
||||
Column('last_modified', DateTime, onupdate=func.utc_timestamp())
|
||||
@@ -147,141 +167,130 @@ Above, the ``create_date`` column will be populated with the result of the
|
||||
or ``CURRENT_TIMESTAMP`` in most cases) during an INSERT statement, and the
|
||||
``key`` column with the result of a SELECT subquery from another table. The
|
||||
``last_modified`` column will be populated with the value of
|
||||
``UTC_TIMESTAMP()``, a function specific to MySQL, when an UPDATE statement is
|
||||
the SQL ``UTC_TIMESTAMP()`` MySQL function when an UPDATE statement is
|
||||
emitted for this table.
|
||||
|
||||
Note that when using ``func`` functions, unlike when using Python `datetime`
|
||||
functions we *do* call the function, i.e. with parenthesis "()" - this is
|
||||
because what we want in this case is the return value of the function, which
|
||||
is the SQL expression construct that will be rendered into the INSERT or
|
||||
UPDATE statement.
|
||||
.. note::
|
||||
|
||||
The above SQL functions are usually executed "inline" with the INSERT or
|
||||
UPDATE statement being executed, meaning, a single statement is executed which
|
||||
embeds the given expressions or subqueries within the VALUES or SET clause of
|
||||
the statement. Although in some cases, the function is "pre-executed" in a
|
||||
SELECT statement of its own beforehand. This happens when all of the following
|
||||
is true:
|
||||
When using SQL functions with the :attr:`.func` construct, we "call" the
|
||||
named function, e.g. with parenthesis as in ``func.now()``. This differs
|
||||
from when we specify a Python callable as a default such as
|
||||
``datetime.datetime``, where we pass the function itself, but we don't
|
||||
invoke it ourselves. In the case of a SQL function, invoking
|
||||
``func.now()`` returns the SQL expression object that will render the
|
||||
"NOW" function into the SQL being emitted.
|
||||
|
||||
* the column is a primary key column
|
||||
* the database dialect does not support a usable ``cursor.lastrowid`` accessor
|
||||
(or equivalent); this currently includes PostgreSQL, Oracle, and Firebird, as
|
||||
well as some MySQL dialects.
|
||||
* the dialect does not support the "RETURNING" clause or similar, or the
|
||||
``implicit_returning`` flag is set to ``False`` for the dialect. Dialects
|
||||
which support RETURNING currently include Postgresql, Oracle, Firebird, and
|
||||
MS-SQL.
|
||||
* the statement is a single execution, i.e. only supplies one set of
|
||||
parameters and doesn't use "executemany" behavior
|
||||
* the ``inline=True`` flag is not set on the
|
||||
:class:`~sqlalchemy.sql.expression.Insert()` or
|
||||
:class:`~sqlalchemy.sql.expression.Update()` construct, and the statement has
|
||||
not defined an explicit `returning()` clause.
|
||||
Default and update SQL expressions specified by :paramref:`.Column.default` and
|
||||
:paramref:`.Column.onupdate` are invoked explicitly by SQLAlchemy when an
|
||||
INSERT or UPDATE statement occurs, typically rendered inline within the DML
|
||||
statement except in certain cases listed below. This is different than a
|
||||
"server side" default, which is part of the table's DDL definition, e.g. as
|
||||
part of the "CREATE TABLE" statement, which are likely more common. For
|
||||
server side defaults, see the next section :ref:`server_defaults`.
|
||||
|
||||
Whether or not the default generation clause "pre-executes" is not something
|
||||
that normally needs to be considered, unless it is being addressed for
|
||||
performance reasons.
|
||||
When a SQL expression indicated by :paramref:`.Column.default` is used with
|
||||
primary key columns, there are some cases where SQLAlchemy must "pre-execute"
|
||||
the default generation SQL function, meaning it is invoked in a separate SELECT
|
||||
statement, and the resulting value is passed as a parameter to the INSERT.
|
||||
This only occurs for primary key columns for an INSERT statement that is being
|
||||
asked to return this primary key value, where RETURNING or ``cursor.lastrowid``
|
||||
may not be used. An :class:`.Insert` construct that specifies the
|
||||
:paramref:`~.expression.insert.inline` flag will always render default expressions
|
||||
inline.
|
||||
|
||||
When the statement is executed with a single set of parameters (that is, it is
|
||||
not an "executemany" style execution), the returned
|
||||
:class:`~sqlalchemy.engine.ResultProxy` will contain a collection
|
||||
accessible via ``result.postfetch_cols()`` which contains a list of all
|
||||
:class:`~sqlalchemy.engine.ResultProxy` will contain a collection accessible
|
||||
via :meth:`.ResultProxy.postfetch_cols` which contains a list of all
|
||||
:class:`~sqlalchemy.schema.Column` objects which had an inline-executed
|
||||
default. Similarly, all parameters which were bound to the statement,
|
||||
including all Python and SQL expressions which were pre-executed, are present
|
||||
in the ``last_inserted_params()`` or ``last_updated_params()`` collections on
|
||||
:class:`~sqlalchemy.engine.ResultProxy`. The ``inserted_primary_key``
|
||||
collection contains a list of primary key values for the row inserted (a list
|
||||
so that single-column and composite-column primary keys are represented in the
|
||||
same format).
|
||||
default. Similarly, all parameters which were bound to the statement, including
|
||||
all Python and SQL expressions which were pre-executed, are present in the
|
||||
:meth:`.ResultProxy.last_inserted_params` or
|
||||
:meth:`.ResultProxy.last_updated_params` collections on
|
||||
:class:`~sqlalchemy.engine.ResultProxy`. The
|
||||
:attr:`.ResultProxy.inserted_primary_key` collection contains a list of primary
|
||||
key values for the row inserted (a list so that single-column and composite-
|
||||
column primary keys are represented in the same format).
|
||||
|
||||
Server Side Defaults
|
||||
--------------------
|
||||
.. _server_defaults:
|
||||
|
||||
A variant on the SQL expression default is the ``server_default``, which gets
|
||||
placed in the CREATE TABLE statement during a ``create()`` operation:
|
||||
Server-invoked DDL-Explicit Default Expressions
|
||||
-----------------------------------------------
|
||||
|
||||
A variant on the SQL expression default is the :paramref:`.Column.server_default`, which gets
|
||||
placed in the CREATE TABLE statement during a :meth:`.Table.create` operation:
|
||||
|
||||
.. sourcecode:: python+sql
|
||||
|
||||
t = Table('test', meta,
|
||||
Column('abc', String(20), server_default='abc'),
|
||||
Column('created_at', DateTime, server_default=text("sysdate"))
|
||||
Column('created_at', DateTime, server_default=func.sysdate()),
|
||||
Column('index_value', Integer, server_default=text("0"))
|
||||
)
|
||||
|
||||
A create call for the above table will produce::
|
||||
|
||||
CREATE TABLE test (
|
||||
abc varchar(20) default 'abc',
|
||||
created_at datetime default sysdate
|
||||
created_at datetime default sysdate,
|
||||
index_value integer default 0
|
||||
)
|
||||
|
||||
The behavior of ``server_default`` is similar to that of a regular SQL
|
||||
default; if it's placed on a primary key column for a database which doesn't
|
||||
have a way to "postfetch" the ID, and the statement is not "inlined", the SQL
|
||||
expression is pre-executed; otherwise, SQLAlchemy lets the default fire off on
|
||||
the database side normally.
|
||||
The above example illustrates the two typical use cases for :paramref:`.Column.server_default`,
|
||||
that of the SQL function (SYSDATE in the above example) as well as a server-side constant
|
||||
value (the integer "0" in the above example). It is advisable to use the
|
||||
:func:`.text` construct for any literal SQL values as opposed to passing the
|
||||
raw value, as SQLAlchemy does not typically perform any quoting or escaping on
|
||||
these values.
|
||||
|
||||
Like client-generated expressions, :paramref:`.Column.server_default` can accommodate
|
||||
SQL expressions in general, however it is expected that these will usually be simple
|
||||
functions and expressions, and not the more complex cases like an embedded SELECT.
|
||||
|
||||
|
||||
.. _triggered_columns:
|
||||
|
||||
Triggered Columns
|
||||
------------------
|
||||
Marking Implicitly Generated Values, timestamps, and Triggered Columns
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Columns with values set by a database trigger or other external process may be
|
||||
called out using :class:`.FetchedValue` as a marker::
|
||||
Columns which generate a new value on INSERT or UPDATE based on other
|
||||
server-side database mechanisms, such as database-specific auto-generating
|
||||
behaviors such as seen with TIMESTAMP columns on some platforms, as well as
|
||||
custom triggers that invoke upon INSERT or UPDATE to generate a new value,
|
||||
may be called out using :class:`.FetchedValue` as a marker::
|
||||
|
||||
t = Table('test', meta,
|
||||
Column('abc', String(20), server_default=FetchedValue()),
|
||||
Column('id', Integer, primary_key=True),
|
||||
Column('abc', TIMESTAMP, server_default=FetchedValue()),
|
||||
Column('def', String(20), server_onupdate=FetchedValue())
|
||||
)
|
||||
|
||||
.. versionchanged:: 0.8.0b2,0.7.10
|
||||
The ``for_update`` argument on :class:`.FetchedValue` is set automatically
|
||||
when specified as the ``server_onupdate`` argument. If using an older version,
|
||||
specify the onupdate above as ``server_onupdate=FetchedValue(for_update=True)``.
|
||||
The :class:`.FetchedValue` indicator does not affect the rendered DDL for the
|
||||
CREATE TABLE. Instead, it marks the column as one that will have a new value
|
||||
populated by the database during the process of an INSERT or UPDATE statement,
|
||||
and for supporting databases may be used to indicate that the column should be
|
||||
part of a RETURNING or OUTPUT clause for the statement. Tools such as the
|
||||
SQLAlchemy ORM then make use of this marker in order to know how to get at the
|
||||
value of the column after such an operation. In particular, the
|
||||
:meth:`.ValuesBase.return_defaults` method can be used with an :class:`.Insert`
|
||||
or :class:`.Update` construct to indicate that these values should be
|
||||
returned.
|
||||
|
||||
These markers do not emit a "default" clause when the table is created,
|
||||
however they do set the same internal flags as a static ``server_default``
|
||||
clause, providing hints to higher-level tools that a "post-fetch" of these
|
||||
rows should be performed after an insert or update.
|
||||
For details on using :class:`.FetchedValue` with the ORM, see
|
||||
:ref:`orm_server_defaults`.
|
||||
|
||||
.. note::
|
||||
.. seealso::
|
||||
|
||||
It's generally not appropriate to use :class:`.FetchedValue` in
|
||||
conjunction with a primary key column, particularly when using the
|
||||
ORM or any other scenario where the :attr:`.ResultProxy.inserted_primary_key`
|
||||
attribute is required. This is becaue the "post-fetch" operation requires
|
||||
that the primary key value already be available, so that the
|
||||
row can be selected on its primary key.
|
||||
|
||||
For a server-generated primary key value, all databases provide special
|
||||
accessors or other techniques in order to acquire the "last inserted
|
||||
primary key" column of a table. These mechanisms aren't affected by the presence
|
||||
of :class:`.FetchedValue`. For special situations where triggers are
|
||||
used to generate primary key values, and the database in use does not
|
||||
support the ``RETURNING`` clause, it may be necessary to forego the usage
|
||||
of the trigger and instead apply the SQL expression or function as a
|
||||
"pre execute" expression::
|
||||
|
||||
t = Table('test', meta,
|
||||
Column('abc', MyType, default=func.generate_new_value(), primary_key=True)
|
||||
)
|
||||
|
||||
Where above, when :meth:`.Table.insert` is used,
|
||||
the ``func.generate_new_value()`` expression will be pre-executed
|
||||
in the context of a scalar ``SELECT`` statement, and the new value will
|
||||
be applied to the subsequent ``INSERT``, while at the same time being
|
||||
made available to the :attr:`.ResultProxy.inserted_primary_key`
|
||||
attribute.
|
||||
:ref:`orm_server_defaults`
|
||||
|
||||
|
||||
Defining Sequences
|
||||
-------------------
|
||||
------------------
|
||||
|
||||
SQLAlchemy represents database sequences using the
|
||||
:class:`~sqlalchemy.schema.Sequence` object, which is considered to be a
|
||||
special case of "column default". It only has an effect on databases which
|
||||
have explicit support for sequences, which currently includes Postgresql,
|
||||
have explicit support for sequences, which currently includes PostgreSQL,
|
||||
Oracle, and Firebird. The :class:`~sqlalchemy.schema.Sequence` object is
|
||||
otherwise ignored.
|
||||
|
||||
@@ -291,7 +300,10 @@ configured to fire off during UPDATE operations if desired. It is most
|
||||
commonly used in conjunction with a single integer primary key column::
|
||||
|
||||
table = Table("cartitems", meta,
|
||||
Column("cart_id", Integer, Sequence('cart_id_seq'), primary_key=True),
|
||||
Column(
|
||||
"cart_id",
|
||||
Integer,
|
||||
Sequence('cart_id_seq', metadata=meta), primary_key=True),
|
||||
Column("description", String(40)),
|
||||
Column("createdate", DateTime())
|
||||
)
|
||||
@@ -299,45 +311,148 @@ commonly used in conjunction with a single integer primary key column::
|
||||
Where above, the table "cartitems" is associated with a sequence named
|
||||
"cart_id_seq". When INSERT statements take place for "cartitems", and no value
|
||||
is passed for the "cart_id" column, the "cart_id_seq" sequence will be used to
|
||||
generate a value.
|
||||
generate a value. Typically, the sequence function is embedded in the
|
||||
INSERT statement, which is combined with RETURNING so that the newly generated
|
||||
value can be returned to the Python code::
|
||||
|
||||
When the :class:`~sqlalchemy.schema.Sequence` is associated with a table,
|
||||
CREATE and DROP statements issued for that table will also issue CREATE/DROP
|
||||
for the sequence object as well, thus "bundling" the sequence object with its
|
||||
parent table.
|
||||
INSERT INTO cartitems (cart_id, description, createdate)
|
||||
VALUES (next_val(cart_id_seq), 'some description', '2015-10-15 12:00:15')
|
||||
RETURNING cart_id
|
||||
|
||||
The :class:`~sqlalchemy.schema.Sequence` object also implements special
|
||||
functionality to accommodate Postgresql's SERIAL datatype. The SERIAL type in
|
||||
PG automatically generates a sequence that is used implicitly during inserts.
|
||||
This means that if a :class:`~sqlalchemy.schema.Table` object defines a
|
||||
:class:`~sqlalchemy.schema.Sequence` on its primary key column so that it
|
||||
works with Oracle and Firebird, the :class:`~sqlalchemy.schema.Sequence` would
|
||||
get in the way of the "implicit" sequence that PG would normally use. For this
|
||||
use case, add the flag ``optional=True`` to the
|
||||
:class:`~sqlalchemy.schema.Sequence` object - this indicates that the
|
||||
:class:`~sqlalchemy.schema.Sequence` should only be used if the database
|
||||
provides no other option for generating primary key identifiers.
|
||||
When the :class:`~sqlalchemy.schema.Sequence` is associated with a
|
||||
:class:`.Column` as its **Python-side** default generator, the
|
||||
:class:`.Sequence` will also be subject to "CREATE SEQUENCE" and "DROP
|
||||
SEQUENCE" DDL when similar DDL is emitted for the owning :class:`.Table`.
|
||||
This is a limited scope convenience feature that does not accommodate for
|
||||
inheritance of other aspects of the :class:`.MetaData`, such as the default
|
||||
schema. Therefore, it is best practice that for a :class:`.Sequence` which
|
||||
is local to a certain :class:`.Column` / :class:`.Table`, that it be
|
||||
explicitly associated with the :class:`.MetaData` using the
|
||||
:paramref:`.Sequence.metadata` parameter. See the section
|
||||
:ref:`sequence_metadata` for more background on this.
|
||||
|
||||
The :class:`~sqlalchemy.schema.Sequence` object also has the ability to be
|
||||
executed standalone like a SQL expression, which has the effect of calling its
|
||||
"next value" function::
|
||||
Associating a Sequence on a SERIAL column
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
seq = Sequence('some_sequence')
|
||||
nextid = connection.execute(seq)
|
||||
PostgreSQL's SERIAL datatype is an auto-incrementing type that implies
|
||||
the implicit creation of a PostgreSQL sequence when CREATE TABLE is emitted.
|
||||
If a :class:`.Column` specifies an explicit :class:`.Sequence` object
|
||||
which also specifies a true value for the :paramref:`.Sequence.optional`
|
||||
boolean flag, the :class:`.Sequence` will not take effect under PostgreSQL,
|
||||
and the SERIAL datatype will proceed normally. Instead, the :class:`.Sequence`
|
||||
will only take effect when used against other sequence-supporting
|
||||
databases, currently Oracle and Firebird.
|
||||
|
||||
Executing a Sequence Standalone
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A SEQUENCE is a first class schema object in SQL and can be used to generate
|
||||
values independently in the database. If you have a :class:`.Sequence`
|
||||
object, it can be invoked with its "next value" instruction by
|
||||
passing it directly to a SQL execution method::
|
||||
|
||||
with my_engine.connect() as conn:
|
||||
seq = Sequence('some_sequence')
|
||||
nextid = conn.execute(seq)
|
||||
|
||||
In order to embed the "next value" function of a :class:`.Sequence`
|
||||
inside of a SQL statement like a SELECT or INSERT, use the :meth:`.Sequence.next_value`
|
||||
method, which will render at statement compilation time a SQL function that is
|
||||
appropriate for the target backend::
|
||||
|
||||
>>> my_seq = Sequence('some_sequence')
|
||||
>>> stmt = select([my_seq.next_value()])
|
||||
>>> print stmt.compile(dialect=postgresql.dialect())
|
||||
SELECT nextval('some_sequence') AS next_value_1
|
||||
|
||||
.. _sequence_metadata:
|
||||
|
||||
Associating a Sequence with the MetaData
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
For many years, the SQLAlchemy documentation referred to the
|
||||
example of associating a :class:`.Sequence` with a table as follows::
|
||||
|
||||
table = Table("cartitems", meta,
|
||||
Column("cart_id", Integer, Sequence('cart_id_seq'),
|
||||
primary_key=True),
|
||||
Column("description", String(40)),
|
||||
Column("createdate", DateTime())
|
||||
)
|
||||
|
||||
While the above is a prominent idiomatic pattern, it is recommended that
|
||||
the :class:`.Sequence` in most cases be explicitly associated with the
|
||||
:class:`.MetaData`, using the :paramref:`.Sequence.metadata` parameter::
|
||||
|
||||
table = Table("cartitems", meta,
|
||||
Column(
|
||||
"cart_id",
|
||||
Integer,
|
||||
Sequence('cart_id_seq', metadata=meta), primary_key=True),
|
||||
Column("description", String(40)),
|
||||
Column("createdate", DateTime())
|
||||
)
|
||||
|
||||
The :class:`.Sequence` object is a first class
|
||||
schema construct that can exist independently of any table in a database, and
|
||||
can also be shared among tables. Therefore SQLAlchemy does not implicitly
|
||||
modify the :class:`.Sequence` when it is associated with a :class:`.Column`
|
||||
object as either the Python-side or server-side default generator. While the
|
||||
CREATE SEQUENCE / DROP SEQUENCE DDL is emitted for a :class:`.Sequence`
|
||||
defined as a Python side generator at the same time the table itself is subject
|
||||
to CREATE or DROP, this is a convenience feature that does not imply that the
|
||||
:class:`.Sequence` is fully associated with the :class:`.MetaData` object.
|
||||
|
||||
Explicitly associating the :class:`.Sequence` with :class:`.MetaData`
|
||||
allows for the following behaviors:
|
||||
|
||||
* The :class:`.Sequence` will inherit the :paramref:`.MetaData.schema`
|
||||
parameter specified to the target :class:`.MetaData`, which
|
||||
affects the production of CREATE / DROP DDL, if any.
|
||||
|
||||
* The :meth:`.Sequence.create` and :meth:`.Sequence.drop` methods
|
||||
automatically use the engine bound to the :class:`.MetaData`
|
||||
object, if any.
|
||||
|
||||
* The :meth:`.MetaData.create_all` and :meth:`.MetaData.drop_all`
|
||||
methods will emit CREATE / DROP for this :class:`.Sequence`,
|
||||
even if the :class:`.Sequence` is not associated with any
|
||||
:class:`.Table` / :class:`.Column` that's a member of this
|
||||
:class:`.MetaData`.
|
||||
|
||||
Since the vast majority of cases that deal with :class:`.Sequence` expect
|
||||
that :class:`.Sequence` to be fully "owned" by the associated :class:`.Table`
|
||||
and that options like default schema are propagated, setting the
|
||||
:paramref:`.Sequence.metadata` parameter should be considered a best practice.
|
||||
|
||||
Associating a Sequence as the Server Side Default
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When we associate a :class:`.Sequence` with a :class:`.Column` as above,
|
||||
this association is an **in-Python only** association. The CREATE TABLE
|
||||
that would be generated for our :class:`.Table` would not refer to this
|
||||
sequence. If we want the sequence to be used as a server-side default,
|
||||
meaning it takes place even if we emit INSERT commands to the table from
|
||||
the SQL commandline, we can use the :paramref:`.Column.server_default`
|
||||
parameter in conjunction with the value-generation function of the
|
||||
sequence, available from the :meth:`.Sequence.next_value` method::
|
||||
.. note:: The following technique is known to work only with the PostgreSQL
|
||||
database. It does not work with Oracle.
|
||||
|
||||
cart_id_seq = Sequence('cart_id_seq')
|
||||
The preceding sections illustrate how to associate a :class:`.Sequence` with a
|
||||
:class:`.Column` as the **Python side default generator**::
|
||||
|
||||
Column(
|
||||
"cart_id", Integer, Sequence('cart_id_seq', metadata=meta),
|
||||
primary_key=True)
|
||||
|
||||
In the above case, the :class:`.Sequence` will automatically be subject
|
||||
to CREATE SEQUENCE / DROP SEQUENCE DDL when the related :class:`.Table`
|
||||
is subject to CREATE / DROP. However, the sequence will **not** be present
|
||||
as the server-side default for the column when CREATE TABLE is emitted.
|
||||
|
||||
If we want the sequence to be used as a server-side default,
|
||||
meaning it takes place even if we emit INSERT commands to the table from
|
||||
the SQL command line, we can use the :paramref:`.Column.server_default`
|
||||
parameter in conjunction with the value-generation function of the
|
||||
sequence, available from the :meth:`.Sequence.next_value` method. Below
|
||||
we illustrate the same :class:`.Sequence` being associated with the
|
||||
:class:`.Column` both as the Python-side default generator as well as
|
||||
the server-side default generator::
|
||||
|
||||
cart_id_seq = Sequence('cart_id_seq', metadata=meta)
|
||||
table = Table("cartitems", meta,
|
||||
Column(
|
||||
"cart_id", Integer, cart_id_seq,
|
||||
@@ -346,7 +461,20 @@ sequence, available from the :meth:`.Sequence.next_value` method::
|
||||
Column("createdate", DateTime())
|
||||
)
|
||||
|
||||
The above metadata will generate a CREATE TABLE statement on Postgresql as::
|
||||
or with the ORM::
|
||||
|
||||
class CartItem(Base):
|
||||
__tablename__ = 'cartitems'
|
||||
|
||||
cart_id_seq = Sequence('cart_id_seq', metadata=Base.metadata)
|
||||
cart_id = Column(
|
||||
Integer, cart_id_seq,
|
||||
server_default=cart_id_seq.next_value(), primary_key=True)
|
||||
description = Column(String(40))
|
||||
createdate = Column(DateTime)
|
||||
|
||||
When the "CREATE TABLE" statement is emitted, on PostgreSQL it would be
|
||||
emitted as::
|
||||
|
||||
CREATE TABLE cartitems (
|
||||
cart_id INTEGER DEFAULT nextval('cart_id_seq') NOT NULL,
|
||||
@@ -355,15 +483,25 @@ The above metadata will generate a CREATE TABLE statement on Postgresql as::
|
||||
PRIMARY KEY (cart_id)
|
||||
)
|
||||
|
||||
We place the :class:`.Sequence` also as a Python-side default above, that
|
||||
is, it is mentioned twice in the :class:`.Column` definition. Depending
|
||||
on the backend in use, this may not be strictly necessary, for example
|
||||
on the Postgresql backend the Core will use ``RETURNING`` to access the
|
||||
newly generated primary key value in any case. However, for the best
|
||||
compatibility, :class:`.Sequence` was originally intended to be a Python-side
|
||||
directive first and foremost so it's probably a good idea to specify it
|
||||
in this way as well.
|
||||
Placement of the :class:`.Sequence` in both the Python-side and server-side
|
||||
default generation contexts ensures that the "primary key fetch" logic
|
||||
works in all cases. Typically, sequence-enabled databases also support
|
||||
RETURNING for INSERT statements, which is used automatically by SQLAlchemy
|
||||
when emitting this statement. However if RETURNING is not used for a particular
|
||||
insert, then SQLAlchemy would prefer to "pre-execute" the sequence outside
|
||||
of the INSERT statement itself, which only works if the sequence is
|
||||
included as the Python-side default generator function.
|
||||
|
||||
The example also associates the :class:`.Sequence` with the enclosing
|
||||
:class:`.MetaData` directly, which again ensures that the :class:`.Sequence`
|
||||
is fully associated with the parameters of the :class:`.MetaData` collection
|
||||
including the default schema, if any.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`postgresql_sequences` - in the PostgreSQL dialect documentation
|
||||
|
||||
:ref:`oracle_returning` - in the Oracle dialect documentation
|
||||
|
||||
Default Objects API
|
||||
-------------------
|
||||
|
||||
Vendored
+29
-18
@@ -42,7 +42,7 @@ applications.
|
||||
.. _supported_dbapis:
|
||||
|
||||
Supported Databases
|
||||
====================
|
||||
===================
|
||||
|
||||
SQLAlchemy includes many :class:`.Dialect` implementations for various
|
||||
backends. Dialects for the most common databases are included with SQLAlchemy; a handful
|
||||
@@ -71,14 +71,26 @@ the database using all lowercase letters. If not specified, a "default" DBAPI
|
||||
will be imported if available - this default is typically the most widely
|
||||
known driver available for that backend.
|
||||
|
||||
Examples for common connection styles follow below. For a full index of
|
||||
detailed information on all included dialects as well as links to third-party dialects, see
|
||||
:ref:`dialect_toplevel`.
|
||||
As the URL is like any other URL, special characters such as those that
|
||||
may be used in the password need to be URL encoded. Below is an example
|
||||
of a URL that includes the password ``"kx%jj5/g"``::
|
||||
|
||||
Postgresql
|
||||
postgresql+pg8000://dbuser:kx%25jj5%2Fg@pghost10/appdb
|
||||
|
||||
The encoding for the above password can be generated using ``urllib``::
|
||||
|
||||
>>> import urllib.parse
|
||||
>>> urllib.parse.quote_plus("kx%jj5/g")
|
||||
'kx%25jj5%2Fg'
|
||||
|
||||
Examples for common connection styles follow below. For a full index of
|
||||
detailed information on all included dialects as well as links to third-party
|
||||
dialects, see :ref:`dialect_toplevel`.
|
||||
|
||||
PostgreSQL
|
||||
----------
|
||||
|
||||
The Postgresql dialect uses psycopg2 as the default DBAPI. pg8000 is
|
||||
The PostgreSQL dialect uses psycopg2 as the default DBAPI. pg8000 is
|
||||
also available as a pure-Python substitute::
|
||||
|
||||
# default
|
||||
@@ -90,7 +102,7 @@ also available as a pure-Python substitute::
|
||||
# pg8000
|
||||
engine = create_engine('postgresql+pg8000://scott:tiger@localhost/mydatabase')
|
||||
|
||||
More notes on connecting to Postgresql at :ref:`postgresql_toplevel`.
|
||||
More notes on connecting to PostgreSQL at :ref:`postgresql_toplevel`.
|
||||
|
||||
MySQL
|
||||
-----
|
||||
@@ -101,14 +113,11 @@ MySQL DBAPIs available, including MySQL-connector-python and OurSQL::
|
||||
# default
|
||||
engine = create_engine('mysql://scott:tiger@localhost/foo')
|
||||
|
||||
# mysql-python
|
||||
# mysqlclient (a maintained fork of MySQL-Python)
|
||||
engine = create_engine('mysql+mysqldb://scott:tiger@localhost/foo')
|
||||
|
||||
# MySQL-connector-python
|
||||
engine = create_engine('mysql+mysqlconnector://scott:tiger@localhost/foo')
|
||||
|
||||
# OurSQL
|
||||
engine = create_engine('mysql+oursql://scott:tiger@localhost/foo')
|
||||
# PyMySQL
|
||||
engine = create_engine('mysql+pymysql://scott:tiger@localhost/foo')
|
||||
|
||||
More notes on connecting to MySQL at :ref:`mysql_toplevel`.
|
||||
|
||||
@@ -153,11 +162,13 @@ For a relative file path, this requires three slashes::
|
||||
|
||||
And for an absolute file path, the three slashes are followed by the absolute path::
|
||||
|
||||
#Unix/Mac - 4 initial slashes in total
|
||||
# Unix/Mac - 4 initial slashes in total
|
||||
engine = create_engine('sqlite:////absolute/path/to/foo.db')
|
||||
#Windows
|
||||
|
||||
# Windows
|
||||
engine = create_engine('sqlite:///C:\\path\\to\\foo.db')
|
||||
#Windows alternative using raw string
|
||||
|
||||
# Windows alternative using raw string
|
||||
engine = create_engine(r'sqlite:///C:\path\to\foo.db')
|
||||
|
||||
To use a SQLite ``:memory:`` database, specify an empty URL::
|
||||
@@ -212,7 +223,7 @@ For more information on connection pooling, see :ref:`pooling_toplevel`.
|
||||
.. _custom_dbapi_args:
|
||||
|
||||
Custom DBAPI connect() arguments
|
||||
=================================
|
||||
================================
|
||||
|
||||
Custom arguments used when issuing the ``connect()`` call to the underlying
|
||||
DBAPI may be issued in three distinct ways. String-based arguments can be
|
||||
@@ -246,7 +257,7 @@ argument, which specifies a callable that returns a DBAPI connection:
|
||||
.. _dbengine_logging:
|
||||
|
||||
Configuring Logging
|
||||
====================
|
||||
===================
|
||||
|
||||
Python's standard `logging
|
||||
<http://docs.python.org/library/logging.html>`_ module is used to
|
||||
|
||||
Vendored
+8
-12
@@ -6,17 +6,13 @@ Events
|
||||
SQLAlchemy includes an event API which publishes a wide variety of hooks into
|
||||
the internals of both SQLAlchemy Core and ORM.
|
||||
|
||||
.. versionadded:: 0.7
|
||||
The system supersedes the previous system of "extension", "proxy",
|
||||
and "listener" classes.
|
||||
|
||||
Event Registration
|
||||
------------------
|
||||
|
||||
Subscribing to an event occurs through a single API point, the :func:`.listen` function,
|
||||
or alternatively the :func:`.listens_for` decorator. These functions
|
||||
accept a user-defined listening function, a string identifier which identifies the event to be
|
||||
intercepted, and a target. Additional positional and keyword arguments to these
|
||||
or alternatively the :func:`.listens_for` decorator. These functions accept a
|
||||
target, a string identifier which identifies the event to be intercepted, and
|
||||
a user-defined listening function. Additional positional and keyword arguments to these
|
||||
two functions may be supported by
|
||||
specific types of events, which may specify alternate interfaces for the given event function, or provide
|
||||
instructions regarding secondary event targets based on the given target.
|
||||
@@ -30,7 +26,7 @@ and that a user-defined listener function should receive two positional argument
|
||||
from sqlalchemy.pool import Pool
|
||||
|
||||
def my_on_connect(dbapi_con, connection_record):
|
||||
print "New DBAPI connection:", dbapi_con
|
||||
print("New DBAPI connection:", dbapi_con)
|
||||
|
||||
listen(Pool, 'connect', my_on_connect)
|
||||
|
||||
@@ -41,7 +37,7 @@ To listen with the :func:`.listens_for` decorator looks like::
|
||||
|
||||
@listens_for(Pool, "connect")
|
||||
def my_on_connect(dbapi_con, connection_record):
|
||||
print "New DBAPI connection:", dbapi_con
|
||||
print("New DBAPI connection:", dbapi_con)
|
||||
|
||||
Named Argument Styles
|
||||
---------------------
|
||||
@@ -117,7 +113,7 @@ and objects::
|
||||
listen(my_engine, 'connect', my_on_connect)
|
||||
|
||||
Modifiers
|
||||
----------
|
||||
---------
|
||||
|
||||
Some listeners allow modifiers to be passed to :func:`.listen`. These
|
||||
modifiers sometimes provide alternate calling signatures for
|
||||
@@ -129,14 +125,14 @@ this value can be supported::
|
||||
def validate_phone(target, value, oldvalue, initiator):
|
||||
"""Strip non-numeric characters from a phone number"""
|
||||
|
||||
return re.sub(r'(?![0-9])', '', value)
|
||||
return re.sub(r'\D', '', value)
|
||||
|
||||
# setup listener on UserContact.phone attribute, instructing
|
||||
# it to use the return value
|
||||
listen(UserContact.phone, 'set', validate_phone, retval=True)
|
||||
|
||||
Event Reference
|
||||
----------------
|
||||
---------------
|
||||
|
||||
Both SQLAlchemy Core and SQLAlchemy ORM feature a wide variety of event hooks:
|
||||
|
||||
|
||||
Vendored
+4
-8
@@ -1,7 +1,7 @@
|
||||
.. _core_event_toplevel:
|
||||
|
||||
Core Events
|
||||
============
|
||||
===========
|
||||
|
||||
This section describes the event interfaces provided in
|
||||
SQLAlchemy Core.
|
||||
@@ -11,18 +11,14 @@ ORM events are described in :ref:`orm_event_toplevel`.
|
||||
.. autoclass:: sqlalchemy.event.base.Events
|
||||
:members:
|
||||
|
||||
.. versionadded:: 0.7
|
||||
The event system supersedes the previous system of "extension", "listener",
|
||||
and "proxy" classes.
|
||||
|
||||
Connection Pool Events
|
||||
-----------------------
|
||||
----------------------
|
||||
|
||||
.. autoclass:: sqlalchemy.events.PoolEvents
|
||||
:members:
|
||||
|
||||
SQL Execution and Connection Events
|
||||
------------------------------------
|
||||
-----------------------------------
|
||||
|
||||
.. autoclass:: sqlalchemy.events.ConnectionEvents
|
||||
:members:
|
||||
@@ -31,7 +27,7 @@ SQL Execution and Connection Events
|
||||
:members:
|
||||
|
||||
Schema Events
|
||||
-----------------------
|
||||
-------------
|
||||
|
||||
.. autoclass:: sqlalchemy.events.DDLEvents
|
||||
:members:
|
||||
|
||||
Vendored
+2
@@ -1,3 +1,5 @@
|
||||
.. _core_exceptions_toplevel:
|
||||
|
||||
Core Exceptions
|
||||
===============
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -1,7 +1,7 @@
|
||||
.. _dep_interfaces_core_toplevel:
|
||||
|
||||
Deprecated Event Interfaces
|
||||
============================
|
||||
===========================
|
||||
|
||||
.. module:: sqlalchemy.interfaces
|
||||
|
||||
|
||||
Vendored
+30
-20
@@ -33,7 +33,7 @@ The remaining positional arguments are mostly
|
||||
Column('user_id', Integer, primary_key=True),
|
||||
Column('user_name', String(16), nullable=False),
|
||||
Column('email_address', String(60)),
|
||||
Column('password', String(20), nullable=False)
|
||||
Column('nickname', String(50), nullable=False)
|
||||
)
|
||||
|
||||
Above, a table called ``user`` is described, which contains four columns. The
|
||||
@@ -45,7 +45,7 @@ Note also that each column describes its datatype using objects corresponding
|
||||
to genericized types, such as :class:`~sqlalchemy.types.Integer` and
|
||||
:class:`~sqlalchemy.types.String`. SQLAlchemy features dozens of types of
|
||||
varying levels of specificity as well as the ability to create custom types.
|
||||
Documentation on the type system can be found at :ref:`types`.
|
||||
Documentation on the type system can be found at :ref:`types_toplevel`.
|
||||
|
||||
Accessing Tables and Columns
|
||||
----------------------------
|
||||
@@ -58,7 +58,7 @@ dependency (that is, each table is preceded by all tables which it
|
||||
references)::
|
||||
|
||||
>>> for t in metadata.sorted_tables:
|
||||
... print t.name
|
||||
... print(t.name)
|
||||
user
|
||||
user_preference
|
||||
invoice
|
||||
@@ -93,15 +93,15 @@ table include::
|
||||
|
||||
# iterate through all columns
|
||||
for c in employees.c:
|
||||
print c
|
||||
print(c)
|
||||
|
||||
# get the table's primary key columns
|
||||
for primary_key in employees.primary_key:
|
||||
print primary_key
|
||||
print(primary_key)
|
||||
|
||||
# get the table's foreign key objects:
|
||||
for fkey in employees.foreign_keys:
|
||||
print fkey
|
||||
print(fkey)
|
||||
|
||||
# access the table's MetaData:
|
||||
employees.metadata
|
||||
@@ -154,7 +154,7 @@ will issue the CREATE statements:
|
||||
Column('user_id', Integer, primary_key=True),
|
||||
Column('user_name', String(16), nullable=False),
|
||||
Column('email_address', String(60), key='email'),
|
||||
Column('password', String(20), nullable=False)
|
||||
Column('nickname', String(50), nullable=False)
|
||||
)
|
||||
|
||||
user_prefs = Table('user_prefs', metadata,
|
||||
@@ -170,7 +170,7 @@ will issue the CREATE statements:
|
||||
user_id INTEGER NOT NULL PRIMARY KEY,
|
||||
user_name VARCHAR(16) NOT NULL,
|
||||
email_address VARCHAR(60),
|
||||
password VARCHAR(20) NOT NULL
|
||||
nickname VARCHAR(50) NOT NULL
|
||||
)
|
||||
PRAGMA table_info(user_prefs){}
|
||||
CREATE TABLE user_prefs(
|
||||
@@ -243,20 +243,18 @@ database schemas in relation to application code using schema migration tools.
|
||||
|
||||
There are two major migration tools available for SQLAlchemy:
|
||||
|
||||
* `Alembic <http://alembic.readthedocs.org>`_ - Written by the author of SQLAlchemy,
|
||||
* `Alembic <https://alembic.sqlalchemy.org>`_ - Written by the author of SQLAlchemy,
|
||||
Alembic features a highly customizable environment and a minimalistic usage pattern,
|
||||
supporting such features as transactional DDL, automatic generation of "candidate"
|
||||
migrations, an "offline" mode which generates SQL scripts, and support for branch
|
||||
resolution.
|
||||
* `SQLAlchemy-Migrate <http://code.google.com/p/sqlalchemy-migrate/>`_ - The original
|
||||
migration tool for SQLAlchemy, SQLAlchemy-Migrate is widely used and continues
|
||||
under active development. SQLAlchemy-Migrate includes features such as
|
||||
SQL script generation, ORM class generation, ORM model comparison, and extensive
|
||||
support for SQLite migrations.
|
||||
* `SQLAlchemy-Migrate <https://github.com/openstack/sqlalchemy-migrate>`_ - The original
|
||||
migration tool for SQLAlchemy, SQLAlchemy-Migrate is still used by projects
|
||||
such as Openstack, however is being superseded by Alembic.
|
||||
|
||||
|
||||
Specifying the Schema Name
|
||||
---------------------------
|
||||
--------------------------
|
||||
|
||||
Some databases support the concept of multiple schemas. A
|
||||
:class:`~sqlalchemy.schema.Table` can reference this by specifying the
|
||||
@@ -303,29 +301,41 @@ described in the individual documentation sections for each dialect.
|
||||
Column, Table, MetaData API
|
||||
---------------------------
|
||||
|
||||
.. attribute:: sqlalchemy.schema.BLANK_SCHEMA
|
||||
|
||||
Symbol indicating that a :class:`.Table` or :class:`.Sequence`
|
||||
should have 'None' for its schema, even if the parent
|
||||
:class:`.MetaData` has specified a schema.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:paramref:`.MetaData.schema`
|
||||
|
||||
:paramref:`.Table.schema`
|
||||
|
||||
:paramref:`.Sequence.schema`
|
||||
|
||||
.. versionadded:: 1.0.14
|
||||
|
||||
|
||||
.. autoclass:: Column
|
||||
:members:
|
||||
:inherited-members:
|
||||
:undoc-members:
|
||||
|
||||
|
||||
.. autoclass:: MetaData
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
|
||||
.. autoclass:: SchemaItem
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
.. autoclass:: Table
|
||||
:members:
|
||||
:inherited-members:
|
||||
:undoc-members:
|
||||
|
||||
|
||||
.. autoclass:: ThreadLocalMetaData
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
|
||||
|
||||
Vendored
+179
-125
@@ -102,7 +102,7 @@ a last resort for when a DBAPI has some form of ``connect``
|
||||
that is not at all supported by SQLAlchemy.
|
||||
|
||||
Constructing a Pool
|
||||
------------------------
|
||||
-------------------
|
||||
|
||||
To use a :class:`.Pool` by itself, the ``creator`` function is
|
||||
the only argument that's required and is passed first, followed
|
||||
@@ -161,6 +161,8 @@ Connection pools support an event interface that allows hooks to execute
|
||||
upon first connect, upon each new connection, and upon checkout and
|
||||
checkin of connections. See :class:`.PoolEvents` for details.
|
||||
|
||||
.. _pool_disconnects:
|
||||
|
||||
Dealing with Disconnects
|
||||
------------------------
|
||||
|
||||
@@ -170,19 +172,140 @@ its entire set of connections, setting the previously pooled connections as
|
||||
when the database server has been restarted, and all previously established connections
|
||||
are no longer functional. There are two approaches to this.
|
||||
|
||||
Disconnect Handling - Optimistic
|
||||
.. _pool_disconnects_pessimistic:
|
||||
|
||||
Disconnect Handling - Pessimistic
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The most common approach is to let SQLAlchemy handle disconnects as they
|
||||
occur, at which point the pool is refreshed. This assumes the :class:`.Pool`
|
||||
is used in conjunction with a :class:`.Engine`. The :class:`.Engine` has
|
||||
logic which can detect disconnection events and refresh the pool automatically.
|
||||
The pessimistic approach refers to emitting a test statement on the SQL
|
||||
connection at the start of each connection pool checkout, to test
|
||||
that the database connection is still viable. Typically, this
|
||||
is a simple statement like "SELECT 1", but may also make use of some
|
||||
DBAPI-specific method to test the connection for liveness.
|
||||
|
||||
The approach adds a small bit of overhead to the connection checkout process,
|
||||
however is otherwise the most simple and reliable approach to completely
|
||||
eliminating database errors due to stale pooled connections. The calling
|
||||
application does not need to be concerned about organizing operations
|
||||
to be able to recover from stale connections checked out from the pool.
|
||||
|
||||
It is critical to note that the pre-ping approach **does not accommodate for
|
||||
connections dropped in the middle of transactions or other SQL operations**.
|
||||
If the database becomes unavailable while a transaction is in progress, the
|
||||
transaction will be lost and the database error will be raised. While
|
||||
the :class:`.Connection` object will detect a "disconnect" situation and
|
||||
recycle the connection as well as invalidate the rest of the connection pool
|
||||
when this condition occurs,
|
||||
the individual operation where the exception was raised will be lost, and it's
|
||||
up to the application to either abandon
|
||||
the operation, or retry the whole transaction again.
|
||||
|
||||
Pessimistic testing of connections upon checkout is achievable by
|
||||
using the :paramref:`.Pool.pre_ping` argument, available from :func:`.create_engine`
|
||||
via the :paramref:`.create_engine.pool_pre_ping` argument::
|
||||
|
||||
engine = create_engine("mysql+pymysql://user:pw@host/db", pool_pre_ping=True)
|
||||
|
||||
The "pre ping" feature will normally emit SQL equivalent to "SELECT 1" each time a
|
||||
connection is checked out from the pool; if an error is raised that is detected
|
||||
as a "disconnect" situation, the connection will be immediately recycled, and
|
||||
all other pooled connections older than the current time are invalidated, so
|
||||
that the next time they are checked out, they will also be recycled before use.
|
||||
|
||||
If the database is still not available when "pre ping" runs, then the initial
|
||||
connect will fail and the error for failure to connect will be propagated
|
||||
normally. In the uncommon situation that the database is available for
|
||||
connections, but is not able to respond to a "ping", the "pre_ping" will try up
|
||||
to three times before giving up, propagating the database error last received.
|
||||
|
||||
.. note::
|
||||
|
||||
the "SELECT 1" emitted by "pre-ping" is invoked within the scope
|
||||
of the connection pool / dialect, using a very short codepath for minimal
|
||||
Python latency. As such, this statement is **not logged in the SQL
|
||||
echo output**, and will not show up in SQLAlchemy's engine logging.
|
||||
|
||||
.. versionadded:: 1.2 Added "pre-ping" capability to the :class:`.Pool`
|
||||
class.
|
||||
|
||||
Custom / Legacy Pessimistic Ping
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Before :paramref:`.create_engine.pool_pre_ping` was added, the "pre-ping"
|
||||
approach historically has been performed manually using
|
||||
the :meth:`.ConnectionEvents.engine_connect` engine event.
|
||||
The most common recipe for this is below, for reference
|
||||
purposes in case an application is already using such a recipe, or special
|
||||
behaviors are needed::
|
||||
|
||||
from sqlalchemy import exc
|
||||
from sqlalchemy import event
|
||||
from sqlalchemy import select
|
||||
|
||||
some_engine = create_engine(...)
|
||||
|
||||
@event.listens_for(some_engine, "engine_connect")
|
||||
def ping_connection(connection, branch):
|
||||
if branch:
|
||||
# "branch" refers to a sub-connection of a connection,
|
||||
# we don't want to bother pinging on these.
|
||||
return
|
||||
|
||||
# turn off "close with result". This flag is only used with
|
||||
# "connectionless" execution, otherwise will be False in any case
|
||||
save_should_close_with_result = connection.should_close_with_result
|
||||
connection.should_close_with_result = False
|
||||
|
||||
try:
|
||||
# run a SELECT 1. use a core select() so that
|
||||
# the SELECT of a scalar value without a table is
|
||||
# appropriately formatted for the backend
|
||||
connection.scalar(select([1]))
|
||||
except exc.DBAPIError as err:
|
||||
# catch SQLAlchemy's DBAPIError, which is a wrapper
|
||||
# for the DBAPI's exception. It includes a .connection_invalidated
|
||||
# attribute which specifies if this connection is a "disconnect"
|
||||
# condition, which is based on inspection of the original exception
|
||||
# by the dialect in use.
|
||||
if err.connection_invalidated:
|
||||
# run the same SELECT again - the connection will re-validate
|
||||
# itself and establish a new connection. The disconnect detection
|
||||
# here also causes the whole connection pool to be invalidated
|
||||
# so that all stale connections are discarded.
|
||||
connection.scalar(select([1]))
|
||||
else:
|
||||
raise
|
||||
finally:
|
||||
# restore "close with result"
|
||||
connection.should_close_with_result = save_should_close_with_result
|
||||
|
||||
The above recipe has the advantage that we are making use of SQLAlchemy's
|
||||
facilities for detecting those DBAPI exceptions that are known to indicate
|
||||
a "disconnect" situation, as well as the :class:`.Engine` object's ability
|
||||
to correctly invalidate the current connection pool when this condition
|
||||
occurs and allowing the current :class:`.Connection` to re-validate onto
|
||||
a new DBAPI connection.
|
||||
|
||||
|
||||
Disconnect Handling - Optimistic
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When pessimistic handling is not employed, as well as when the database is
|
||||
shutdown and/or restarted in the middle of a connection's period of use within
|
||||
a transaction, the other approach to dealing with stale / closed connections is
|
||||
to let SQLAlchemy handle disconnects as they occur, at which point all
|
||||
connections in the pool are invalidated, meaning they are assumed to be
|
||||
stale and will be refreshed upon next checkout. This behavior assumes the
|
||||
:class:`.Pool` is used in conjunction with a :class:`.Engine`.
|
||||
The :class:`.Engine` has logic which can detect
|
||||
disconnection events and refresh the pool automatically.
|
||||
|
||||
When the :class:`.Connection` attempts to use a DBAPI connection, and an
|
||||
exception is raised that corresponds to a "disconnect" event, the connection
|
||||
is invalidated. The :class:`.Connection` then calls the :meth:`.Pool.recreate`
|
||||
method, effectively invalidating all connections not currently checked out so
|
||||
that they are replaced with new ones upon next checkout::
|
||||
that they are replaced with new ones upon next checkout. This flow is
|
||||
illustrated by the code example below::
|
||||
|
||||
from sqlalchemy import create_engine, exc
|
||||
e = create_engine(...)
|
||||
@@ -195,22 +318,26 @@ that they are replaced with new ones upon next checkout::
|
||||
except exc.DBAPIError, e:
|
||||
# an exception is raised, Connection is invalidated.
|
||||
if e.connection_invalidated:
|
||||
print "Connection was invalidated!"
|
||||
print("Connection was invalidated!")
|
||||
|
||||
# after the invalidate event, a new connection
|
||||
# starts with a new Pool
|
||||
c = e.connect()
|
||||
c.execute("SELECT * FROM table")
|
||||
|
||||
The above example illustrates that no special intervention is needed, the pool
|
||||
continues normally after a disconnection event is detected. However, an exception is
|
||||
raised. In a typical web application using an ORM Session, the above condition would
|
||||
The above example illustrates that no special intervention is needed to
|
||||
refresh the pool, which continues normally after a disconnection event is
|
||||
detected. However, one database exception is raised, per each connection
|
||||
that is in use while the database unavailability event occurred.
|
||||
In a typical web application using an ORM Session, the above condition would
|
||||
correspond to a single request failing with a 500 error, then the web application
|
||||
continuing normally beyond that. Hence the approach is "optimistic" in that frequent
|
||||
database restarts are not anticipated.
|
||||
|
||||
.. _pool_setting_recycle:
|
||||
|
||||
Setting Pool Recycle
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
An additional setting that can augment the "optimistic" approach is to set the
|
||||
pool recycle parameter. This parameter prevents the pool from using a particular
|
||||
@@ -226,65 +353,6 @@ upon next checkout. Note that the invalidation **only** occurs during checkout
|
||||
any connections that are held in a checked out state. ``pool_recycle`` is a function
|
||||
of the :class:`.Pool` itself, independent of whether or not an :class:`.Engine` is in use.
|
||||
|
||||
.. _pool_disconnects_pessimistic:
|
||||
|
||||
Disconnect Handling - Pessimistic
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
At the expense of some extra SQL emitted for each connection checked out from the pool,
|
||||
a "ping" operation established by a checkout event handler
|
||||
can detect an invalid connection before it is used::
|
||||
|
||||
from sqlalchemy import exc
|
||||
from sqlalchemy import event
|
||||
from sqlalchemy.pool import Pool
|
||||
|
||||
@event.listens_for(Pool, "checkout")
|
||||
def ping_connection(dbapi_connection, connection_record, connection_proxy):
|
||||
cursor = dbapi_connection.cursor()
|
||||
try:
|
||||
cursor.execute("SELECT 1")
|
||||
except:
|
||||
# optional - dispose the whole pool
|
||||
# instead of invalidating one at a time
|
||||
# connection_proxy._pool.dispose()
|
||||
|
||||
# raise DisconnectionError - pool will try
|
||||
# connecting again up to three times before raising.
|
||||
raise exc.DisconnectionError()
|
||||
cursor.close()
|
||||
|
||||
Above, the :class:`.Pool` object specifically catches :class:`~sqlalchemy.exc.DisconnectionError` and attempts
|
||||
to create a new DBAPI connection, up to three times, before giving up and then raising
|
||||
:class:`~sqlalchemy.exc.InvalidRequestError`, failing the connection. This recipe will ensure
|
||||
that a new :class:`.Connection` will succeed even if connections
|
||||
in the pool have gone stale, provided that the database server is actually running. The expense
|
||||
is that of an additional execution performed per checkout. When using the ORM :class:`.Session`,
|
||||
there is one connection checkout per transaction, so the expense is fairly low. The ping approach
|
||||
above also works with straight connection pool usage, that is, even if no :class:`.Engine` were
|
||||
involved.
|
||||
|
||||
The event handler can be tested using a script like the following, restarting the database
|
||||
server at the point at which the script pauses for input::
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
e = create_engine("mysql://scott:tiger@localhost/test", echo_pool=True)
|
||||
c1 = e.connect()
|
||||
c2 = e.connect()
|
||||
c3 = e.connect()
|
||||
c1.close()
|
||||
c2.close()
|
||||
c3.close()
|
||||
|
||||
# pool size is now three.
|
||||
|
||||
print "Restart the server"
|
||||
raw_input()
|
||||
|
||||
for i in xrange(10):
|
||||
c = e.connect()
|
||||
print c.execute("select 1").fetchall()
|
||||
c.close()
|
||||
|
||||
.. _pool_connection_invalidation:
|
||||
|
||||
@@ -328,6 +396,41 @@ a DBAPI connection might be invalidated include:
|
||||
All invalidations which occur will invoke the :meth:`.PoolEvents.invalidate`
|
||||
event.
|
||||
|
||||
.. _pool_use_lifo:
|
||||
|
||||
Using FIFO vs. LIFO
|
||||
-------------------
|
||||
|
||||
The :class:`.QueuePool` class features a flag called
|
||||
:paramref:`.QueuePool.use_lifo`, which can also be accessed from
|
||||
:func:`.create_engine` via the flag :paramref:`.create_engine.pool_use_lifo`.
|
||||
Setting this flag to ``True`` causes the pool's "queue" behavior to instead be
|
||||
that of a "stack", e.g. the last connection to be returned to the pool is the
|
||||
first one to be used on the next request. In contrast to the pool's long-
|
||||
standing behavior of first-in-first-out, which produces a round-robin effect of
|
||||
using each connection in the pool in series, lifo mode allows excess
|
||||
connections to remain idle in the pool, allowing server-side timeout schemes to
|
||||
close these connections out. The difference between FIFO and LIFO is
|
||||
basically whether or not its desirable for the pool to keep a full set of
|
||||
connections ready to go even during idle periods::
|
||||
|
||||
engine = create_engine(
|
||||
"postgreql://", pool_use_lifo=True, pool_pre_ping=True)
|
||||
|
||||
Above, we also make use of the :paramref:`.create_engine.pool_pre_ping` flag
|
||||
so that connections which are closed from the server side are gracefully
|
||||
handled by the connection pool and replaced with a new connection.
|
||||
|
||||
Note that the flag only applies to :class:`.QueuePool` use.
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`pool_disconnects`
|
||||
|
||||
|
||||
|
||||
Using Connection Pools with Multiprocessing
|
||||
-------------------------------------------
|
||||
|
||||
@@ -347,12 +450,12 @@ connections from the pool so that it makes all new ones. Below is
|
||||
a simple version using ``multiprocessing.Process``, but this idea
|
||||
should be adapted to the style of forking in use::
|
||||
|
||||
eng = create_engine("...")
|
||||
engine = create_engine("...")
|
||||
|
||||
def run_in_process():
|
||||
eng.dispose()
|
||||
engine.dispose()
|
||||
|
||||
with eng.connect() as conn:
|
||||
with engine.connect() as conn:
|
||||
conn.execute("...")
|
||||
|
||||
p = Process(target=run_in_process)
|
||||
@@ -365,7 +468,7 @@ This is a little more magical but probably more foolproof::
|
||||
from sqlalchemy import exc
|
||||
import os
|
||||
|
||||
eng = create_engine("...")
|
||||
engine = create_engine("...")
|
||||
|
||||
@event.listens_for(engine, "connect")
|
||||
def connect(dbapi_connection, connection_record):
|
||||
@@ -390,7 +493,7 @@ coercing the pool to recycle the connection record to make a new connection.
|
||||
|
||||
|
||||
API Documentation - Available Pool Implementations
|
||||
---------------------------------------------------
|
||||
--------------------------------------------------
|
||||
|
||||
.. autoclass:: sqlalchemy.pool.Pool
|
||||
|
||||
@@ -426,52 +529,3 @@ API Documentation - Available Pool Implementations
|
||||
.. autoclass:: _ConnectionRecord
|
||||
:members:
|
||||
|
||||
|
||||
Pooling Plain DB-API Connections
|
||||
--------------------------------
|
||||
|
||||
Any :pep:`249` DB-API module can be "proxied" through the connection
|
||||
pool transparently. Usage of the DB-API is exactly as before, except
|
||||
the ``connect()`` method will consult the pool. Below we illustrate
|
||||
this with ``psycopg2``::
|
||||
|
||||
import sqlalchemy.pool as pool
|
||||
import psycopg2 as psycopg
|
||||
|
||||
psycopg = pool.manage(psycopg)
|
||||
|
||||
# then connect normally
|
||||
connection = psycopg.connect(database='test', username='scott',
|
||||
password='tiger')
|
||||
|
||||
This produces a :class:`_DBProxy` object which supports the same
|
||||
``connect()`` function as the original DB-API module. Upon
|
||||
connection, a connection proxy object is returned, which delegates its
|
||||
calls to a real DB-API connection object. This connection object is
|
||||
stored persistently within a connection pool (an instance of
|
||||
:class:`.Pool`) that corresponds to the exact connection arguments sent
|
||||
to the ``connect()`` function.
|
||||
|
||||
The connection proxy supports all of the methods on the original
|
||||
connection object, most of which are proxied via ``__getattr__()``.
|
||||
The ``close()`` method will return the connection to the pool, and the
|
||||
``cursor()`` method will return a proxied cursor object. Both the
|
||||
connection proxy and the cursor proxy will also return the underlying
|
||||
connection to the pool after they have both been garbage collected,
|
||||
which is detected via weakref callbacks (``__del__`` is not used).
|
||||
|
||||
Additionally, when connections are returned to the pool, a
|
||||
``rollback()`` is issued on the connection unconditionally. This is
|
||||
to release any locks still held by the connection that may have
|
||||
resulted from normal activity.
|
||||
|
||||
By default, the ``connect()`` method will return the same connection
|
||||
that is already checked out in the current thread. This allows a
|
||||
particular connection to be used in a given thread without needing to
|
||||
pass it around between functions. To disable this behavior, specify
|
||||
``use_threadlocal=False`` to the ``manage()`` function.
|
||||
|
||||
.. autofunction:: sqlalchemy.pool.manage
|
||||
|
||||
.. autofunction:: sqlalchemy.pool.clear_managers
|
||||
|
||||
|
||||
Vendored
+5
-5
@@ -55,7 +55,7 @@ hasn't already been loaded; once loaded, new calls to
|
||||
reflection queries.
|
||||
|
||||
Overriding Reflected Columns
|
||||
-----------------------------
|
||||
----------------------------
|
||||
|
||||
Individual columns can be overridden with explicit values when reflecting
|
||||
tables; this is handy for specifying custom datatypes, constraints such as
|
||||
@@ -67,7 +67,7 @@ primary keys that may not be configured within the database, etc.::
|
||||
... autoload=True)
|
||||
|
||||
Reflecting Views
|
||||
-----------------
|
||||
----------------
|
||||
|
||||
The reflection system can also reflect views. Basic usage is the same as that
|
||||
of a table::
|
||||
@@ -125,7 +125,7 @@ database is also available. This is known as the "Inspector"::
|
||||
from sqlalchemy.engine import reflection
|
||||
engine = create_engine('...')
|
||||
insp = reflection.Inspector.from_engine(engine)
|
||||
print insp.get_table_names()
|
||||
print(insp.get_table_names())
|
||||
|
||||
.. autoclass:: sqlalchemy.engine.reflection.Inspector
|
||||
:members:
|
||||
@@ -156,8 +156,8 @@ different format than what was specified in SQLAlchemy. The :class:`.Table`
|
||||
objects returned from reflection cannot be always relied upon to produce the identical
|
||||
DDL as the original Python-defined :class:`.Table` objects. Areas where
|
||||
this occurs includes server defaults, column-associated sequences and various
|
||||
idosyncrasies regarding constraints and datatypes. Server side defaults may
|
||||
be returned with cast directives (typically Postgresql will include a ``::<type>``
|
||||
idiosyncrasies regarding constraints and datatypes. Server side defaults may
|
||||
be returned with cast directives (typically PostgreSQL will include a ``::<type>``
|
||||
cast) or different quoting patterns than originally specified.
|
||||
|
||||
Another category of limitation includes schema structures for which reflection
|
||||
|
||||
Vendored
+17
@@ -23,6 +23,8 @@ elements are themselves :class:`.ColumnElement` subclasses).
|
||||
|
||||
.. autofunction:: join
|
||||
|
||||
.. autofunction:: lateral
|
||||
|
||||
.. autofunction:: outerjoin
|
||||
|
||||
.. autofunction:: select
|
||||
@@ -31,6 +33,8 @@ elements are themselves :class:`.ColumnElement` subclasses).
|
||||
|
||||
.. autofunction:: sqlalchemy.sql.expression.table
|
||||
|
||||
.. autofunction:: tablesample
|
||||
|
||||
.. autofunction:: union
|
||||
|
||||
.. autofunction:: union_all
|
||||
@@ -57,6 +61,9 @@ elements are themselves :class:`.ColumnElement` subclasses).
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
.. autoclass:: HasCTE
|
||||
:members:
|
||||
|
||||
.. autoclass:: HasPrefixes
|
||||
:members:
|
||||
|
||||
@@ -67,6 +74,10 @@ elements are themselves :class:`.ColumnElement` subclasses).
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
.. autoclass:: Lateral
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
.. autoclass:: ScalarSelect
|
||||
:members:
|
||||
|
||||
@@ -79,10 +90,16 @@ elements are themselves :class:`.ColumnElement` subclasses).
|
||||
|
||||
.. autoclass:: SelectBase
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
.. autoclass:: TableClause
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
.. autoclass:: TableSample
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
.. autoclass:: TextAsFrom
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
Vendored
+26
-5
@@ -3,14 +3,23 @@ Column Elements and Expressions
|
||||
|
||||
.. module:: sqlalchemy.sql.expression
|
||||
|
||||
The most fundamental part of the SQL expression API are the "column elements",
|
||||
which allow for basic SQL expression support. The core of all SQL expression
|
||||
constructs is the :class:`.ClauseElement`, which is the base for several
|
||||
sub-branches. The :class:`.ColumnElement` class is the fundamental unit
|
||||
used to construct any kind of typed SQL expression.
|
||||
The expression API consists of a series of classes that each represent a
|
||||
specific lexical element within a SQL string. Composed together
|
||||
into a larger structure, they form a statement construct that may
|
||||
be *compiled* into a string representation that can be passed to a database.
|
||||
The classes are organized into a
|
||||
hierarchy that begins at the basemost ClauseElement class. Key subclasses
|
||||
include ColumnElement, which represents the role of any column-based expression
|
||||
in a SQL statement, such as in the columns clause, WHERE clause, and ORDER BY
|
||||
clause, and FromClause, which represents the role of a token that is placed in
|
||||
the FROM clause of a SELECT statement.
|
||||
|
||||
.. autofunction:: all_
|
||||
|
||||
.. autofunction:: and_
|
||||
|
||||
.. autofunction:: any_
|
||||
|
||||
.. autofunction:: asc
|
||||
|
||||
.. autofunction:: between
|
||||
@@ -65,6 +74,8 @@ used to construct any kind of typed SQL expression.
|
||||
|
||||
.. autofunction:: type_coerce
|
||||
|
||||
.. autofunction:: within_group
|
||||
|
||||
.. autoclass:: BinaryExpression
|
||||
:members:
|
||||
|
||||
@@ -129,9 +140,15 @@ used to construct any kind of typed SQL expression.
|
||||
.. autoclass:: Tuple
|
||||
:members:
|
||||
|
||||
.. autoclass:: WithinGroup
|
||||
:members:
|
||||
|
||||
.. autoclass:: sqlalchemy.sql.elements.True_
|
||||
:members:
|
||||
|
||||
.. autoclass:: TypeCoerce
|
||||
:members:
|
||||
|
||||
.. autoclass:: sqlalchemy.sql.operators.custom_op
|
||||
:members:
|
||||
|
||||
@@ -141,6 +158,10 @@ used to construct any kind of typed SQL expression.
|
||||
|
||||
.. autoclass:: sqlalchemy.sql.elements.quoted_name
|
||||
|
||||
.. attribute:: quote
|
||||
|
||||
whether the string should be unconditionally quoted
|
||||
|
||||
.. autoclass:: UnaryExpression
|
||||
:members:
|
||||
|
||||
|
||||
Vendored
+459
-164
File diff suppressed because it is too large
Load Diff
Vendored
+4
-2
@@ -3,7 +3,7 @@
|
||||
.. _types_api:
|
||||
|
||||
Base Type API
|
||||
--------------
|
||||
-------------
|
||||
|
||||
.. autoclass:: TypeEngine
|
||||
:members:
|
||||
@@ -11,9 +11,11 @@ Base Type API
|
||||
|
||||
.. autoclass:: Concatenable
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
|
||||
.. autoclass:: Indexable
|
||||
:members:
|
||||
|
||||
.. autoclass:: NullType
|
||||
|
||||
|
||||
|
||||
Vendored
+19
-9
@@ -18,7 +18,6 @@ the database driver returns an incorrect type.
|
||||
... Column('login', String(32))
|
||||
... )
|
||||
|
||||
|
||||
SQLAlchemy will use the ``Integer`` and ``String(32)`` type
|
||||
information when issuing a ``CREATE TABLE`` statement and will use it
|
||||
again when reading back rows ``SELECTed`` from the database.
|
||||
@@ -35,8 +34,8 @@ Generic types specify a column that can read, write and store a
|
||||
particular type of Python data. SQLAlchemy will choose the best
|
||||
database column type available on the target database when issuing a
|
||||
``CREATE TABLE`` statement. For complete control over which column
|
||||
type is emitted in ``CREATE TABLE``, such as ``VARCHAR`` see `SQL
|
||||
Standard Types`_ and the other sections of this chapter.
|
||||
type is emitted in ``CREATE TABLE``, such as ``VARCHAR`` see
|
||||
:ref:`types_sqlstandard` and the other sections of this chapter.
|
||||
|
||||
.. autoclass:: BigInteger
|
||||
:members:
|
||||
@@ -98,12 +97,19 @@ Standard Types`_ and the other sections of this chapter.
|
||||
|
||||
.. _types_sqlstandard:
|
||||
|
||||
SQL Standard Types
|
||||
------------------
|
||||
SQL Standard and Multiple Vendor Types
|
||||
--------------------------------------
|
||||
|
||||
The SQL standard types always create database column types of the same
|
||||
name when ``CREATE TABLE`` is issued. Some types may not be supported
|
||||
on all databases.
|
||||
This category of types refers to types that are either part of the
|
||||
SQL standard, or are potentially found within a subset of database backends.
|
||||
Unlike the "generic" types, the SQL standard/multi-vendor types have **no**
|
||||
guarantee of working on all backends, and will only work on those backends
|
||||
that explicitly support them by name. That is, the type will always emit
|
||||
its exact name in DDL with ``CREATE TABLE`` is issued.
|
||||
|
||||
|
||||
.. autoclass:: ARRAY
|
||||
:members:
|
||||
|
||||
.. autoclass:: BIGINT
|
||||
|
||||
@@ -137,6 +143,9 @@ on all databases.
|
||||
|
||||
.. autoclass:: INT
|
||||
|
||||
.. autoclass:: JSON
|
||||
:members:
|
||||
|
||||
|
||||
.. autoclass:: sqlalchemy.types.INTEGER
|
||||
|
||||
@@ -163,6 +172,7 @@ on all databases.
|
||||
|
||||
|
||||
.. autoclass:: TIMESTAMP
|
||||
:members:
|
||||
|
||||
|
||||
.. autoclass:: VARBINARY
|
||||
@@ -213,7 +223,7 @@ implemented for that backend::
|
||||
)
|
||||
|
||||
Where above, the INTEGER and VARCHAR types are ultimately from
|
||||
sqlalchemy.types, and INET is specific to the Postgresql dialect.
|
||||
sqlalchemy.types, and INET is specific to the PostgreSQL dialect.
|
||||
|
||||
Some dialect level types have the same name as the SQL standard type,
|
||||
but also provide additional arguments. For example, MySQL implements
|
||||
|
||||
Vendored
+15
-47
@@ -16,12 +16,12 @@ Included Dialects
|
||||
:maxdepth: 1
|
||||
:glob:
|
||||
|
||||
firebird
|
||||
mssql
|
||||
mysql
|
||||
oracle
|
||||
postgresql
|
||||
mysql
|
||||
sqlite
|
||||
oracle
|
||||
mssql
|
||||
firebird
|
||||
sybase
|
||||
|
||||
.. _external_toplevel:
|
||||
@@ -29,52 +29,20 @@ Included Dialects
|
||||
External Dialects
|
||||
-----------------
|
||||
|
||||
.. versionchanged:: 0.8
|
||||
As of SQLAlchemy 0.8, several dialects have been moved to external
|
||||
projects, and dialects for new databases will also be published
|
||||
as external projects. The rationale here is to keep the base
|
||||
SQLAlchemy install and test suite from growing inordinately large.
|
||||
Currently maintained external dialect projects for SQLAlchemy include:
|
||||
|
||||
The "classic" dialects such as SQLite, MySQL, Postgresql, Oracle,
|
||||
SQL Server, and Firebird will remain in the Core for the time being.
|
||||
|
||||
.. versionchanged:: 1.0
|
||||
The Drizzle dialect has been moved into the third party system.
|
||||
|
||||
Current external dialect projects for SQLAlchemy include:
|
||||
|
||||
Production Ready
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
* `ibm_db_sa <http://code.google.com/p/ibm-db/wiki/README>`_ - driver for IBM DB2 and Informix,
|
||||
developed jointly by IBM and SQLAlchemy developers.
|
||||
* `redshift-sqlalchemy <https://pypi.python.org/pypi/redshift-sqlalchemy>`_ - driver for Amazon Redshift, adapts
|
||||
the existing Postgresql/psycopg2 driver.
|
||||
* `ibm_db_sa <http://code.google.com/p/ibm-db/wiki/README>`_ - driver for IBM DB2 and Informix.
|
||||
* `PyHive <https://github.com/dropbox/PyHive#sqlalchemy>`_ - driver for `Apache Hive <https://hive.apache.org/>`_ and `Presto <https://prestodb.github.io/>`_.
|
||||
* `sqlalchemy-redshift <https://pypi.python.org/pypi/sqlalchemy-redshift>`_ - driver for Amazon Redshift, adapts
|
||||
the existing PostgreSQL/psycopg2 driver.
|
||||
* `sqlalchemy-drill <https://github.com/JohnOmernik/sqlalchemy-drill>`_ - driver for Apache Drill.
|
||||
* `sqlalchemy-hana <https://github.com/SAP/sqlalchemy-hana>`_ - driver for SAP Hana.
|
||||
* `sqlalchemy_exasol <https://github.com/blue-yonder/sqlalchemy_exasol>`_ - driver for EXASolution.
|
||||
* `sqlalchemy-sqlany <https://github.com/sqlanywhere/sqlalchemy-sqlany>`_ - driver for SAP Sybase SQL
|
||||
Anywhere, developed by SAP.
|
||||
* `sqlalchemy-monetdb <https://github.com/gijzelaerr/sqlalchemy-monetdb>`_ - driver for MonetDB.
|
||||
|
||||
Experimental / Incomplete
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Dialects that are in an incomplete state or are considered somewhat experimental.
|
||||
|
||||
* `CALCHIPAN <https://bitbucket.org/zzzeek/calchipan/>`_ - Adapts `Pandas <http://pandas.pydata.org/>`_ dataframes to SQLAlchemy.
|
||||
* `sqlalchemy-cubrid <https://bitbucket.org/zzzeek/sqlalchemy-cubrid>`_ - driver for the CUBRID database.
|
||||
|
||||
Attic
|
||||
^^^^^
|
||||
|
||||
Dialects in the "attic" are those that were contributed for SQLAlchemy long ago
|
||||
but have received little attention or demand since then, and are now moved out to
|
||||
their own repositories in at best a semi-working state.
|
||||
Community members interested in these dialects should feel free to pick up on
|
||||
their current codebase and fork off into working libraries.
|
||||
|
||||
* `sqlalchemy-access <https://bitbucket.org/zzzeek/sqlalchemy-access>`_ - driver for Microsoft Access.
|
||||
* `sqlalchemy-drizzle <https://bitbucket.org/zzzeek/sqlalchemy-drizzle>`_ - driver for the Drizzle MySQL variant.
|
||||
* `sqlalchemy-informixdb <https://bitbucket.org/zzzeek/sqlalchemy-informixdb>`_ - driver for the informixdb DBAPI.
|
||||
* `sqlalchemy-maxdb <https://bitbucket.org/zzzeek/sqlalchemy-maxdb>`_ - driver for the MaxDB database
|
||||
|
||||
|
||||
* `snowflake-sqlalchemy <https://github.com/snowflakedb/snowflake-sqlalchemy>`_ - driver for `Snowflake <https://www.snowflake.net/>`_.
|
||||
* `sqlalchemy-tds <https://github.com/m32/sqlalchemy-tds>`_ - driver for MS-SQL,
|
||||
on top of `python-tds <https://github.com/denisenkom/pytds>`_.
|
||||
* `crate <https://github.com/crate/crate-python>`_ - driver for `CrateDB <https://crate.io/>`_.
|
||||
|
||||
Vendored
+28
-20
@@ -6,7 +6,7 @@ Microsoft SQL Server
|
||||
.. automodule:: sqlalchemy.dialects.mssql.base
|
||||
|
||||
SQL Server Data Types
|
||||
-----------------------
|
||||
---------------------
|
||||
|
||||
As with all SQLAlchemy dialects, all UPPERCASE types that are known to be
|
||||
valid with SQL server are importable from the top level dialect, whether
|
||||
@@ -26,75 +26,83 @@ construction arguments, are as follows:
|
||||
|
||||
.. autoclass:: BIT
|
||||
:members: __init__
|
||||
|
||||
|
||||
|
||||
.. autoclass:: CHAR
|
||||
:members: __init__
|
||||
|
||||
|
||||
|
||||
.. autoclass:: DATETIME2
|
||||
:members: __init__
|
||||
|
||||
|
||||
|
||||
.. autoclass:: DATETIMEOFFSET
|
||||
:members: __init__
|
||||
|
||||
|
||||
|
||||
.. autoclass:: IMAGE
|
||||
:members: __init__
|
||||
|
||||
|
||||
|
||||
.. autoclass:: MONEY
|
||||
:members: __init__
|
||||
|
||||
|
||||
|
||||
.. autoclass:: NCHAR
|
||||
:members: __init__
|
||||
|
||||
|
||||
|
||||
.. autoclass:: NTEXT
|
||||
:members: __init__
|
||||
|
||||
|
||||
|
||||
.. autoclass:: NVARCHAR
|
||||
:members: __init__
|
||||
|
||||
|
||||
|
||||
.. autoclass:: REAL
|
||||
:members: __init__
|
||||
|
||||
|
||||
.. autoclass:: ROWVERSION
|
||||
:members: __init__
|
||||
|
||||
.. autoclass:: SMALLDATETIME
|
||||
:members: __init__
|
||||
|
||||
|
||||
|
||||
.. autoclass:: SMALLMONEY
|
||||
:members: __init__
|
||||
|
||||
|
||||
|
||||
.. autoclass:: SQL_VARIANT
|
||||
:members: __init__
|
||||
|
||||
|
||||
|
||||
.. autoclass:: TEXT
|
||||
:members: __init__
|
||||
|
||||
|
||||
|
||||
.. autoclass:: TIME
|
||||
:members: __init__
|
||||
|
||||
|
||||
|
||||
.. autoclass:: TIMESTAMP
|
||||
:members: __init__
|
||||
|
||||
.. autoclass:: TINYINT
|
||||
:members: __init__
|
||||
|
||||
|
||||
|
||||
.. autoclass:: UNIQUEIDENTIFIER
|
||||
:members: __init__
|
||||
|
||||
|
||||
|
||||
.. autoclass:: VARCHAR
|
||||
:members: __init__
|
||||
|
||||
|
||||
|
||||
.. autoclass:: XML
|
||||
:members: __init__
|
||||
|
||||
|
||||
PyODBC
|
||||
@@ -110,7 +118,7 @@ pymssql
|
||||
.. automodule:: sqlalchemy.dialects.mssql.pymssql
|
||||
|
||||
zxjdbc
|
||||
--------------
|
||||
------
|
||||
|
||||
.. automodule:: sqlalchemy.dialects.mssql.zxjdbc
|
||||
|
||||
|
||||
Vendored
+21
-10
@@ -6,7 +6,7 @@ MySQL
|
||||
.. automodule:: sqlalchemy.dialects.mysql.base
|
||||
|
||||
MySQL Data Types
|
||||
------------------
|
||||
----------------
|
||||
|
||||
As with all SQLAlchemy dialects, all UPPERCASE types that are known to be
|
||||
valid with MySQL are importable from the top level dialect::
|
||||
@@ -74,6 +74,8 @@ construction arguments, are as follows:
|
||||
.. autoclass:: INTEGER
|
||||
:members: __init__
|
||||
|
||||
.. autoclass:: JSON
|
||||
:members:
|
||||
|
||||
.. autoclass:: LONGBLOB
|
||||
:members: __init__
|
||||
@@ -154,34 +156,43 @@ construction arguments, are as follows:
|
||||
.. autoclass:: YEAR
|
||||
:members: __init__
|
||||
|
||||
MySQL DML Constructs
|
||||
-------------------------
|
||||
|
||||
MySQL-Python
|
||||
--------------------
|
||||
.. autofunction:: sqlalchemy.dialects.mysql.dml.insert
|
||||
|
||||
.. autoclass:: sqlalchemy.dialects.mysql.dml.Insert
|
||||
:members:
|
||||
|
||||
|
||||
|
||||
mysqlclient (fork of MySQL-Python)
|
||||
----------------------------------
|
||||
|
||||
.. automodule:: sqlalchemy.dialects.mysql.mysqldb
|
||||
|
||||
pymysql
|
||||
-------------
|
||||
PyMySQL
|
||||
-------
|
||||
|
||||
.. automodule:: sqlalchemy.dialects.mysql.pymysql
|
||||
|
||||
MySQL-Connector
|
||||
----------------------
|
||||
---------------
|
||||
|
||||
.. automodule:: sqlalchemy.dialects.mysql.mysqlconnector
|
||||
|
||||
cymysql
|
||||
------------
|
||||
-------
|
||||
|
||||
.. automodule:: sqlalchemy.dialects.mysql.cymysql
|
||||
|
||||
OurSQL
|
||||
--------------
|
||||
------
|
||||
|
||||
.. automodule:: sqlalchemy.dialects.mysql.oursql
|
||||
|
||||
Google App Engine
|
||||
-----------------------
|
||||
-----------------
|
||||
|
||||
.. automodule:: sqlalchemy.dialects.mysql.gaerdbms
|
||||
|
||||
@@ -191,6 +202,6 @@ pyodbc
|
||||
.. automodule:: sqlalchemy.dialects.mysql.pyodbc
|
||||
|
||||
zxjdbc
|
||||
--------------
|
||||
------
|
||||
|
||||
.. automodule:: sqlalchemy.dialects.mysql.zxjdbc
|
||||
|
||||
Vendored
+7
-4
@@ -6,7 +6,7 @@ Oracle
|
||||
.. automodule:: sqlalchemy.dialects.oracle.base
|
||||
|
||||
Oracle Data Types
|
||||
-------------------
|
||||
-----------------
|
||||
|
||||
As with all SQLAlchemy dialects, all UPPERCASE types that are known to be
|
||||
valid with Oracle are importable from the top level dialect, whether
|
||||
@@ -14,10 +14,13 @@ they originate from :mod:`sqlalchemy.types` or from the local dialect::
|
||||
|
||||
from sqlalchemy.dialects.oracle import \
|
||||
BFILE, BLOB, CHAR, CLOB, DATE, \
|
||||
DOUBLE_PRECISION, FLOAT, INTERVAL, LONG, NCLOB, \
|
||||
DOUBLE_PRECISION, FLOAT, INTERVAL, LONG, NCLOB, NCHAR, \
|
||||
NUMBER, NVARCHAR, NVARCHAR2, RAW, TIMESTAMP, VARCHAR, \
|
||||
VARCHAR2
|
||||
|
||||
.. versionadded:: 1.2.19 Added :class:`.NCHAR` to the list of datatypes
|
||||
exported by the Oracle dialect.
|
||||
|
||||
Types which are specific to Oracle, or have Oracle-specific
|
||||
construction arguments, are as follows:
|
||||
|
||||
@@ -54,11 +57,11 @@ construction arguments, are as follows:
|
||||
|
||||
|
||||
cx_Oracle
|
||||
----------
|
||||
---------
|
||||
|
||||
.. automodule:: sqlalchemy.dialects.oracle.cx_oracle
|
||||
|
||||
zxjdbc
|
||||
-------
|
||||
------
|
||||
|
||||
.. automodule:: sqlalchemy.dialects.oracle.zxjdbc
|
||||
|
||||
Vendored
+39
-30
@@ -6,16 +6,16 @@ PostgreSQL
|
||||
.. automodule:: sqlalchemy.dialects.postgresql.base
|
||||
|
||||
PostgreSQL Data Types
|
||||
------------------------
|
||||
---------------------
|
||||
|
||||
As with all SQLAlchemy dialects, all UPPERCASE types that are known to be
|
||||
valid with Postgresql are importable from the top level dialect, whether
|
||||
valid with PostgreSQL are importable from the top level dialect, whether
|
||||
they originate from :mod:`sqlalchemy.types` or from the local dialect::
|
||||
|
||||
from sqlalchemy.dialects.postgresql import \
|
||||
ARRAY, BIGINT, BIT, BOOLEAN, BYTEA, CHAR, CIDR, DATE, \
|
||||
DOUBLE_PRECISION, ENUM, FLOAT, HSTORE, INET, INTEGER, \
|
||||
INTERVAL, JSON, JSONB, MACADDR, NUMERIC, OID, REAL, SMALLINT, TEXT, \
|
||||
INTERVAL, JSON, JSONB, MACADDR, MONEY, NUMERIC, OID, REAL, SMALLINT, TEXT, \
|
||||
TIME, TIMESTAMP, UUID, VARCHAR, INT4RANGE, INT8RANGE, NUMRANGE, \
|
||||
DATERANGE, TSRANGE, TSTZRANGE, TSVECTOR
|
||||
|
||||
@@ -24,26 +24,25 @@ construction arguments, are as follows:
|
||||
|
||||
.. currentmodule:: sqlalchemy.dialects.postgresql
|
||||
|
||||
.. autoclass:: aggregate_order_by
|
||||
|
||||
.. autoclass:: array
|
||||
|
||||
.. autoclass:: ARRAY
|
||||
:members: __init__, Comparator
|
||||
|
||||
.. autofunction:: array_agg
|
||||
|
||||
.. autoclass:: Any
|
||||
.. autofunction:: Any
|
||||
|
||||
.. autoclass:: All
|
||||
.. autofunction:: All
|
||||
|
||||
.. autoclass:: BIT
|
||||
:members: __init__
|
||||
|
||||
|
||||
.. autoclass:: BYTEA
|
||||
:members: __init__
|
||||
|
||||
|
||||
.. autoclass:: CIDR
|
||||
:members: __init__
|
||||
|
||||
|
||||
.. autoclass:: DOUBLE_PRECISION
|
||||
@@ -63,8 +62,6 @@ construction arguments, are as follows:
|
||||
|
||||
|
||||
.. autoclass:: INET
|
||||
:members: __init__
|
||||
|
||||
|
||||
.. autoclass:: INTERVAL
|
||||
:members: __init__
|
||||
@@ -75,20 +72,18 @@ construction arguments, are as follows:
|
||||
.. autoclass:: JSONB
|
||||
:members:
|
||||
|
||||
.. autoclass:: JSONElement
|
||||
:members:
|
||||
|
||||
.. autoclass:: MACADDR
|
||||
:members: __init__
|
||||
|
||||
.. autoclass:: MONEY
|
||||
|
||||
.. autoclass:: OID
|
||||
:members: __init__
|
||||
|
||||
.. autoclass:: REAL
|
||||
:members: __init__
|
||||
|
||||
.. autoclass:: REGCLASS
|
||||
|
||||
.. autoclass:: TSVECTOR
|
||||
:members: __init__
|
||||
|
||||
.. autoclass:: UUID
|
||||
:members: __init__
|
||||
@@ -126,19 +121,19 @@ mixin:
|
||||
|
||||
.. warning::
|
||||
|
||||
The range type DDL support should work with any Postgres DBAPI
|
||||
The range type DDL support should work with any PostgreSQL DBAPI
|
||||
driver, however the data types returned may vary. If you are using
|
||||
``psycopg2``, it's recommended to upgrade to version 2.5 or later
|
||||
before using these column types.
|
||||
|
||||
When instantiating models that use these column types, you should pass
|
||||
whatever data type is expected by the DBAPI driver you're using for
|
||||
the column type. For :mod:`psycopg2` these are
|
||||
:class:`~psycopg2.extras.NumericRange`,
|
||||
:class:`~psycopg2.extras.DateRange`,
|
||||
:class:`~psycopg2.extras.DateTimeRange` and
|
||||
:class:`~psycopg2.extras.DateTimeTZRange` or the class you've
|
||||
registered with :func:`~psycopg2.extras.register_range`.
|
||||
the column type. For ``psycopg2`` these are
|
||||
``psycopg2.extras.NumericRange``,
|
||||
``psycopg2.extras.DateRange``,
|
||||
``psycopg2.extras.DateTimeRange`` and
|
||||
``psycopg2.extras.DateTimeTZRange`` or the class you've
|
||||
registered with ``psycopg2.extras.register_range``.
|
||||
|
||||
For example:
|
||||
|
||||
@@ -162,7 +157,7 @@ For example:
|
||||
PostgreSQL Constraint Types
|
||||
---------------------------
|
||||
|
||||
SQLAlchemy supports Postgresql EXCLUDE constraints via the
|
||||
SQLAlchemy supports PostgreSQL EXCLUDE constraints via the
|
||||
:class:`ExcludeConstraint` class:
|
||||
|
||||
.. autoclass:: ExcludeConstraint
|
||||
@@ -183,29 +178,43 @@ For example::
|
||||
ExcludeConstraint(('room', '='), ('during', '&&')),
|
||||
)
|
||||
|
||||
PostgreSQL DML Constructs
|
||||
-------------------------
|
||||
|
||||
.. autofunction:: sqlalchemy.dialects.postgresql.dml.insert
|
||||
|
||||
.. autoclass:: sqlalchemy.dialects.postgresql.dml.Insert
|
||||
:members:
|
||||
|
||||
psycopg2
|
||||
--------------
|
||||
--------
|
||||
|
||||
.. automodule:: sqlalchemy.dialects.postgresql.psycopg2
|
||||
|
||||
pg8000
|
||||
--------------
|
||||
------
|
||||
|
||||
.. automodule:: sqlalchemy.dialects.postgresql.pg8000
|
||||
|
||||
psycopg2cffi
|
||||
--------------
|
||||
------------
|
||||
|
||||
.. automodule:: sqlalchemy.dialects.postgresql.psycopg2cffi
|
||||
|
||||
py-postgresql
|
||||
--------------------
|
||||
-------------
|
||||
|
||||
.. automodule:: sqlalchemy.dialects.postgresql.pypostgresql
|
||||
|
||||
.. _dialect-postgresql-pygresql:
|
||||
|
||||
pygresql
|
||||
--------
|
||||
|
||||
.. automodule:: sqlalchemy.dialects.postgresql.pygresql
|
||||
|
||||
zxjdbc
|
||||
--------------
|
||||
------
|
||||
|
||||
.. automodule:: sqlalchemy.dialects.postgresql.zxjdbc
|
||||
|
||||
|
||||
Vendored
+4
-2
@@ -6,7 +6,7 @@ SQLite
|
||||
.. automodule:: sqlalchemy.dialects.sqlite.base
|
||||
|
||||
SQLite Data Types
|
||||
------------------------
|
||||
-----------------
|
||||
|
||||
As with all SQLAlchemy dialects, all UPPERCASE types that are known to be
|
||||
valid with SQLite are importable from the top level dialect, whether
|
||||
@@ -14,7 +14,7 @@ they originate from :mod:`sqlalchemy.types` or from the local dialect::
|
||||
|
||||
from sqlalchemy.dialects.sqlite import \
|
||||
BLOB, BOOLEAN, CHAR, DATE, DATETIME, DECIMAL, FLOAT, \
|
||||
INTEGER, NUMERIC, SMALLINT, TEXT, TIME, TIMESTAMP, \
|
||||
INTEGER, NUMERIC, JSON, SMALLINT, TEXT, TIME, TIMESTAMP, \
|
||||
VARCHAR
|
||||
|
||||
.. module:: sqlalchemy.dialects.sqlite
|
||||
@@ -23,6 +23,8 @@ they originate from :mod:`sqlalchemy.types` or from the local dialect::
|
||||
|
||||
.. autoclass:: DATE
|
||||
|
||||
.. autoclass:: JSON
|
||||
|
||||
.. autoclass:: TIME
|
||||
|
||||
Pysqlite
|
||||
|
||||
Vendored
+3
-3
@@ -6,17 +6,17 @@ Sybase
|
||||
.. automodule:: sqlalchemy.dialects.sybase.base
|
||||
|
||||
python-sybase
|
||||
-------------------
|
||||
-------------
|
||||
|
||||
.. automodule:: sqlalchemy.dialects.sybase.pysybase
|
||||
|
||||
pyodbc
|
||||
------------
|
||||
------
|
||||
|
||||
.. automodule:: sqlalchemy.dialects.sybase.pyodbc
|
||||
|
||||
mxodbc
|
||||
------------
|
||||
------
|
||||
|
||||
.. automodule:: sqlalchemy.dialects.sybase.mxodbc
|
||||
|
||||
|
||||
Vendored
+550
@@ -0,0 +1,550 @@
|
||||
:orphan:
|
||||
|
||||
.. _errors:
|
||||
|
||||
==============
|
||||
Error Messages
|
||||
==============
|
||||
|
||||
This section lists descriptions and background for common error messages
|
||||
and warnings raised or emitted by SQLAlchemy.
|
||||
|
||||
SQLAlchemy normally raises errors within the context of a SQLAlchemy-specific
|
||||
exception class. For details on these classes, see
|
||||
:ref:`core_exceptions_toplevel` and :ref:`orm_exceptions_toplevel`.
|
||||
|
||||
SQLAlchemy errors can roughly be separated into two categories, the
|
||||
**programming-time error** and the **runtime error**. Programming-time
|
||||
errors are raised as a result of functions or methods being called with
|
||||
incorrect arguments, or from other configuration-oriented methods such as
|
||||
mapper configurations that can't be resolved. The programming-time error is
|
||||
typically immediate and deterministic. The runtime error on the other hand
|
||||
represents a failure that occurs as a program runs in response to some
|
||||
condition that occurs arbitrarily, such as database connections being
|
||||
exhausted or some data-related issue occurring. Runtime errors are more
|
||||
likely to be seen in the logs of a running application as the program
|
||||
encounters these states in response to load and data being encountered.
|
||||
|
||||
Since runtime errors are not as easy to reproduce and often occur in response
|
||||
to some arbitrary condition as the program runs, they are more difficult to
|
||||
debug and also affect programs that have already been put into production.
|
||||
|
||||
Within this section, the goal is to try to provide background on some of the
|
||||
most common runtime errors as well as programming time errors.
|
||||
|
||||
|
||||
Connections and Transactions
|
||||
============================
|
||||
|
||||
.. _error_3o7r:
|
||||
|
||||
QueuePool limit of size <x> overflow <y> reached, connection timed out, timeout <z>
|
||||
-----------------------------------------------------------------------------------
|
||||
|
||||
This is possibly the most common runtime error experienced, as it directly
|
||||
involves the work load of the application surpassing a configured limit, one
|
||||
which typically applies to nearly all SQLAlchemy applications.
|
||||
|
||||
The following points summarize what this error means, beginning with the
|
||||
most fundamental points that most SQLAlchemy users should already be
|
||||
familiar with.
|
||||
|
||||
* **The SQLAlchemy Engine object uses a pool of connections by default** - What
|
||||
this means is that when one makes use of a SQL database connection resource
|
||||
of an :class:`.Engine` object, and then :term:`releases` that resource,
|
||||
the database connection itself remains connected to the database and
|
||||
is returned to an internal queue where it can be used again. Even though
|
||||
the code may appear to be ending its conversation with the database, in many
|
||||
cases the application will still maintain a fixed number of database connections
|
||||
that persist until the application ends or the pool is explicitly disposed.
|
||||
|
||||
* Because of the pool, when an application makes use of a SQL database
|
||||
connection, most typically from either making use of :meth:`.Engine.connect`
|
||||
or when making queries using an ORM :class:`.Session`, this activity
|
||||
does not necessarily establish a new connection to the database at the
|
||||
moment the connection object is acquired; it instead consults the
|
||||
connection pool for a connection, which will often retrieve an existing
|
||||
connection from the pool to be re-used. If no connections are available,
|
||||
the pool will create a new database connection, but only if the
|
||||
pool has not surpassed a configured capacity.
|
||||
|
||||
* The default pool used in most cases is called :class:`.QueuePool`. When
|
||||
you ask this pool to give you a connection and none are available, it
|
||||
will create a new connection **if the total number of connections in play
|
||||
are less than a configured value**. This value is equal to the
|
||||
**pool size plus the max overflow**. That means if you have configured
|
||||
your engine as::
|
||||
|
||||
engine = create_engine("mysql://u:p@host/db", pool_size=10, max_overflow=20)
|
||||
|
||||
The above :class:`.Engine` will allow **at most 30 connections** to be in
|
||||
play at any time, not including connections that were detached from the
|
||||
engine or invalidated. If a request for a new connection arrives and
|
||||
30 connections are already in use by other parts of the application,
|
||||
the connection pool will block for a fixed period of time,
|
||||
before timing out and raising this error message.
|
||||
|
||||
In order to allow for a higher number of connections be in use at once,
|
||||
the pool can be adjusted using the
|
||||
:paramref:`.create_engine.pool_size` and :paramref:`.create_engine.max_overflow`
|
||||
parameters as passed to the :func:`.create_engine` function. The timeout
|
||||
to wait for a connection to be available is configured using the
|
||||
:paramref:`.create_engine.pool_timeout` parameter.
|
||||
|
||||
* The pool can be configured to have unlimited overflow by setting
|
||||
:paramref:`.create_engine.max_overflow` to the value "-1". With this setting,
|
||||
the pool will still maintain a fixed pool of connections, however it will
|
||||
never block upon a new connection being requested; it will instead unconditionally
|
||||
make a new connection if none are available.
|
||||
|
||||
However, when running in this way, if the application has an issue where it
|
||||
is using up all available connectivity resources, it will eventually hit the
|
||||
configured limit of available connections on the database itself, which will
|
||||
again return an error. More seriously, when the application exhausts the
|
||||
database of connections, it usually will have caused a great
|
||||
amount of resources to be used up before failing, and can also interfere
|
||||
with other applications and database status mechanisms that rely upon being
|
||||
able to connect to the database.
|
||||
|
||||
Given the above, the connection pool can be looked at as a **safety valve
|
||||
for connection use**, providing a critical layer of protection against
|
||||
a rogue application causing the entire database to become unavailable
|
||||
to all other applications. When receiving this error message, it is vastly
|
||||
preferable to repair the issue using up too many connections and/or
|
||||
configure the limits appropriately, rather than allowing for unlimited
|
||||
overflow which does not actually solve the underlying issue.
|
||||
|
||||
What causes an application to use up all the connections that it has available?
|
||||
|
||||
* **The application is fielding too many concurrent requests to do work based
|
||||
on the configured value for the pool** - This is the most straightforward
|
||||
cause. If you have
|
||||
an application that runs in a thread pool that allows for 30 concurrent
|
||||
threads, with one connection in use per thread, if your pool is not configured
|
||||
to allow at least 30 connections checked out at once, you will get this
|
||||
error once your application receives enough concurrent requests. Solution
|
||||
is to raise the limits on the pool or lower the number of concurrent threads.
|
||||
|
||||
* **The application is not returning connections to the pool** - This is the
|
||||
next most common reason, which is that the application is making use of the
|
||||
connection pool, but the program is failing to :term:`release` these
|
||||
connections and is instead leaving them open. The connection pool as well
|
||||
as the ORM :class:`.Session` do have logic such that when the session and/or
|
||||
connection object is garbage collected, it results in the underlying
|
||||
connection resources being released, however this behavior cannot be relied
|
||||
upon to release resources in a timely manner.
|
||||
|
||||
A common reason this can occur is that the application uses ORM sessions and
|
||||
does not call :meth:`.Session.close` upon them one the work involving that
|
||||
session is complete. Solution is to make sure ORM sessions if using the ORM,
|
||||
or engine-bound :class:`.Connection` objects if using Core, are explicitly
|
||||
closed at the end of the work being done, either via the appropriate
|
||||
``.close()`` method, or by using one of the available context managers (e.g.
|
||||
"with:" statement) to properly release the resource.
|
||||
|
||||
* **The application is attempting to run long-running transactions** - A
|
||||
database transaction is a very expensive resource, and should **never be
|
||||
left idle waiting for some event to occur**. If an application is waiting
|
||||
for a user to push a button, or a result to come off of a long running job
|
||||
queue, or is holding a persistent connection open to a browser, **don't
|
||||
keep a database transaction open for the whole time**. As the application
|
||||
needs to work with the database and interact with an event, open a short-lived
|
||||
transaction at that point and then close it.
|
||||
|
||||
* **The application is deadlocking** - Also a common cause of this error and
|
||||
more difficult to grasp, if an application is not able to complete its use
|
||||
of a connection either due to an application-side or database-side deadlock,
|
||||
the application can use up all the available connections which then leads to
|
||||
additional requests receiving this error. Reasons for deadlocks include:
|
||||
|
||||
* Using an implicit async system such as gevent or eventlet without
|
||||
properly monkeypatching all socket libraries and drivers, or which
|
||||
has bugs in not fully covering for all monkeypatched driver methods,
|
||||
or less commonly when the async system is being used against CPU-bound
|
||||
workloads and greenlets making use of database resources are simply waiting
|
||||
too long to attend to them. Neither implicit nor explicit async
|
||||
programming frameworks are typically
|
||||
necessary or appropriate for the vast majority of relational database
|
||||
operations; if an application must use an async system for some area
|
||||
of functionality, it's best that database-oriented business methods
|
||||
run within traditional threads that pass messages to the async part
|
||||
of the application.
|
||||
|
||||
* A database side deadlock, e.g. rows are mutually deadlocked
|
||||
|
||||
* Threading errors, such as mutexes in a mutual deadlock, or calling
|
||||
upon an already locked mutex in the same thread
|
||||
|
||||
Keep in mind an alternative to using pooling is to turn off pooling entirely.
|
||||
See the section :ref:`pool_switching` for background on this. However, note
|
||||
that when this error message is occurring, it is **always** due to a bigger
|
||||
problem in the application itself; the pool just helps to reveal the problem
|
||||
sooner.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`pooling_toplevel`
|
||||
|
||||
:ref:`connections_toplevel`
|
||||
|
||||
|
||||
.. _error_dbapi:
|
||||
|
||||
DBAPI Errors
|
||||
============
|
||||
|
||||
The Python database API, or DBAPI, is a specification for database drivers
|
||||
which can be located at `Pep-249 <https://www.python.org/dev/peps/pep-0249/>`_.
|
||||
This API specifies a set of exception classes that accommodate the full range
|
||||
of failure modes of the database.
|
||||
|
||||
SQLAlchemy does not generate these exceptions directly. Instead, they are
|
||||
intercepted from the database driver and wrapped by the SQLAlchemy-provided
|
||||
exception :class:`.DBAPIError`, however the messaging within the exception is
|
||||
**generated by the driver, not SQLAlchemy**.
|
||||
|
||||
.. _error_rvf5:
|
||||
|
||||
InterfaceError
|
||||
--------------
|
||||
|
||||
Exception raised for errors that are related to the database interface rather
|
||||
than the database itself.
|
||||
|
||||
This error is a :ref:`DBAPI Error <error_dbapi>` and originates from
|
||||
the database driver (DBAPI), not SQLAlchemy itself.
|
||||
|
||||
The ``InterfaceError`` is sometimes raised by drivers in the context
|
||||
of the database connection being dropped, or not being able to connect
|
||||
to the database. For tips on how to deal with this, see the section
|
||||
:ref:`pool_disconnects`.
|
||||
|
||||
.. _error_4xp6:
|
||||
|
||||
DatabaseError
|
||||
--------------
|
||||
|
||||
Exception raised for errors that are related to the database itself, and not
|
||||
the interface or data being passed.
|
||||
|
||||
This error is a :ref:`DBAPI Error <error_dbapi>` and originates from
|
||||
the database driver (DBAPI), not SQLAlchemy itself.
|
||||
|
||||
.. _error_9h9h:
|
||||
|
||||
DataError
|
||||
---------
|
||||
|
||||
Exception raised for errors that are due to problems with the processed data
|
||||
like division by zero, numeric value out of range, etc.
|
||||
|
||||
This error is a :ref:`DBAPI Error <error_dbapi>` and originates from
|
||||
the database driver (DBAPI), not SQLAlchemy itself.
|
||||
|
||||
.. _error_e3q8:
|
||||
|
||||
OperationalError
|
||||
-----------------
|
||||
|
||||
Exception raised for errors that are related to the database's operation and
|
||||
not necessarily under the control of the programmer, e.g. an unexpected
|
||||
disconnect occurs, the data source name is not found, a transaction could not
|
||||
be processed, a memory allocation error occurred during processing, etc.
|
||||
|
||||
This error is a :ref:`DBAPI Error <error_dbapi>` and originates from
|
||||
the database driver (DBAPI), not SQLAlchemy itself.
|
||||
|
||||
The ``OperationalError`` is the most common (but not the only) error class used
|
||||
by drivers in the context of the database connection being dropped, or not
|
||||
being able to connect to the database. For tips on how to deal with this, see
|
||||
the section :ref:`pool_disconnects`.
|
||||
|
||||
.. _error_gkpj:
|
||||
|
||||
IntegrityError
|
||||
--------------
|
||||
|
||||
Exception raised when the relational integrity of the database is affected,
|
||||
e.g. a foreign key check fails.
|
||||
|
||||
This error is a :ref:`DBAPI Error <error_dbapi>` and originates from
|
||||
the database driver (DBAPI), not SQLAlchemy itself.
|
||||
|
||||
.. _error_2j85:
|
||||
|
||||
InternalError
|
||||
-------------
|
||||
|
||||
Exception raised when the database encounters an internal error, e.g. the
|
||||
cursor is not valid anymore, the transaction is out of sync, etc.
|
||||
|
||||
This error is a :ref:`DBAPI Error <error_dbapi>` and originates from
|
||||
the database driver (DBAPI), not SQLAlchemy itself.
|
||||
|
||||
The ``InternalError`` is sometimes raised by drivers in the context
|
||||
of the database connection being dropped, or not being able to connect
|
||||
to the database. For tips on how to deal with this, see the section
|
||||
:ref:`pool_disconnects`.
|
||||
|
||||
.. _error_f405:
|
||||
|
||||
ProgrammingError
|
||||
----------------
|
||||
|
||||
Exception raised for programming errors, e.g. table not found or already
|
||||
exists, syntax error in the SQL statement, wrong number of parameters
|
||||
specified, etc.
|
||||
|
||||
This error is a :ref:`DBAPI Error <error_dbapi>` and originates from
|
||||
the database driver (DBAPI), not SQLAlchemy itself.
|
||||
|
||||
The ``ProgrammingError`` is sometimes raised by drivers in the context
|
||||
of the database connection being dropped, or not being able to connect
|
||||
to the database. For tips on how to deal with this, see the section
|
||||
:ref:`pool_disconnects`.
|
||||
|
||||
.. _error_tw8g:
|
||||
|
||||
NotSupportedError
|
||||
------------------
|
||||
|
||||
Exception raised in case a method or database API was used which is not
|
||||
supported by the database, e.g. requesting a .rollback() on a connection that
|
||||
does not support transaction or has transactions turned off.
|
||||
|
||||
This error is a :ref:`DBAPI Error <error_dbapi>` and originates from
|
||||
the database driver (DBAPI), not SQLAlchemy itself.
|
||||
|
||||
SQL Expression Language
|
||||
=======================
|
||||
|
||||
TypeError: <operator> not supported between instances of 'ColumnProperty' and <something>
|
||||
-----------------------------------------------------------------------------------------
|
||||
|
||||
This often occurs when attempting to use a :func:`.column_property` or
|
||||
:func:`.deferred` object in the context of a SQL expression, usually within
|
||||
declarative such as::
|
||||
|
||||
class Bar(Base):
|
||||
__tablename__ = 'bar'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
cprop = deferred(Column(Integer))
|
||||
|
||||
__table_args__ = (
|
||||
CheckConstraint(cprop > 5),
|
||||
)
|
||||
|
||||
Above, the ``cprop`` attribute is used inline before it has been mapped,
|
||||
however this ``cprop`` attribute is not a :class:`.Column`,
|
||||
it's a :class:`.ColumnProperty`, which is an interim object and therefore
|
||||
does not have the full functionality of either the :class:`.Column` object
|
||||
or the :class:`.InstrmentedAttribute` object that will be mapped onto the
|
||||
``Bar`` class once the declarative process is complete.
|
||||
|
||||
While the :class:`.ColumnProperty` does have a ``__clause_element__()`` method,
|
||||
which allows it to work in some column-oriented contexts, it can't work in an
|
||||
open-ended comparison context as illustrated above, since it has no Python
|
||||
``__eq__()`` method that would allow it to interpret the comparison to the
|
||||
number "5" as a SQL expression and not a regular Python comparison.
|
||||
|
||||
The solution is to access the :class:`.Column` directly using the
|
||||
:attr:`.ColumnProperty.expression` attribute::
|
||||
|
||||
class Bar(Base):
|
||||
__tablename__ = 'bar'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
cprop = deferred(Column(Integer))
|
||||
|
||||
__table_args__ = (
|
||||
CheckConstraint(cprop.expression > 5),
|
||||
)
|
||||
|
||||
|
||||
.. _error_2afi:
|
||||
|
||||
This Compiled object is not bound to any Engine or Connection
|
||||
-------------------------------------------------------------
|
||||
|
||||
This error refers to the concept of "bound metadata", described at
|
||||
:ref:`dbengine_implicit`. The issue occurs when one invokes the
|
||||
:meth:`.Executable.execute` method directly off of a Core expression object
|
||||
that is not associated with any :class:`.Engine`::
|
||||
|
||||
metadata = MetaData()
|
||||
table = Table('t', metadata, Column('q', Integer))
|
||||
|
||||
stmt = select([table])
|
||||
result = stmt.execute() # <--- raises
|
||||
|
||||
What the logic is expecting is that the :class:`.MetaData` object has
|
||||
been **bound** to a :class:`.Engine`::
|
||||
|
||||
engine = create_engine("mysql+pymysql://user:pass@host/db")
|
||||
metadata = MetaData(bind=engine)
|
||||
|
||||
Where above, any statement that derives from a :class:`.Table` which
|
||||
in turn derives from that :class:`.MetaData` will implicitly make use of
|
||||
the given :class:`.Engine` in order to invoke the statement.
|
||||
|
||||
Note that the concept of bound metadata is a **legacy pattern** and in most
|
||||
cases is **highly discouraged**. The best way to invoke the statement is
|
||||
to pass it to the :meth:`.Connection.execute` method of a :class:`.Connection`::
|
||||
|
||||
with engine.connect() as conn:
|
||||
result = conn.execute(stmt)
|
||||
|
||||
When using the ORM, a similar facility is available via the :class:`.Session`::
|
||||
|
||||
result = session.exxecute(stmt)
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`dbengine_implicit`
|
||||
|
||||
|
||||
.. _error_cd3x:
|
||||
|
||||
A value is required for bind parameter <x> (in parameter group <y>)
|
||||
-------------------------------------------------------------------
|
||||
|
||||
This error occurs when a statement makes use of :func:`.bindparam` either
|
||||
implicitly or explicitly and does not provide a value when the statement
|
||||
is executed::
|
||||
|
||||
stmt = select([table.c.column]).where(table.c.id == bindparam('my_param'))
|
||||
|
||||
result = conn.execute(stmt)
|
||||
|
||||
Above, no value has been provided for the parameter "my_param". The correct
|
||||
approach is to provide a value::
|
||||
|
||||
result = conn.execute(stmt, my_param=12)
|
||||
|
||||
When the message takes the form "a value is required for bind parameter <x>
|
||||
in parameter group <y>", the message is referring to the "executemany" style
|
||||
of execution. In this case, the statement is typically an INSERT, UPDATE,
|
||||
or DELETE and a list of parameters is being passed. In this format, the
|
||||
statement may be generated dynamically to include parameter positions for
|
||||
every parameter given in the argument list, where it will use the
|
||||
**first set of parameters** to determine what these should be.
|
||||
|
||||
For example, the statement below is calculated based on the first parameter
|
||||
set to require the parameters, "a", "b", and "c" - these names determine
|
||||
the final string format of the statement which will be used for each
|
||||
set of parameters in the list. As the second entry does not contain "b",
|
||||
this error is generated::
|
||||
|
||||
m = MetaData()
|
||||
t = Table(
|
||||
't', m,
|
||||
Column('a', Integer),
|
||||
Column('b', Integer),
|
||||
Column('c', Integer)
|
||||
)
|
||||
|
||||
e.execute(
|
||||
t.insert(), [
|
||||
{"a": 1, "b": 2, "c": 3},
|
||||
{"a": 2, "c": 4},
|
||||
{"a": 3, "b": 4, "c": 5},
|
||||
]
|
||||
)
|
||||
|
||||
sqlalchemy.exc.StatementError: (sqlalchemy.exc.InvalidRequestError)
|
||||
A value is required for bind parameter 'b', in parameter group 1
|
||||
[SQL: u'INSERT INTO t (a, b, c) VALUES (?, ?, ?)']
|
||||
[parameters: [{'a': 1, 'c': 3, 'b': 2}, {'a': 2, 'c': 4}, {'a': 3, 'c': 5, 'b': 4}]]
|
||||
|
||||
Since "b" is required, pass it as ``None`` so that the INSERT may proceed::
|
||||
|
||||
e.execute(
|
||||
t.insert(), [
|
||||
{"a": 1, "b": 2, "c": 3},
|
||||
{"a": 2, "b": None, "c": 4},
|
||||
{"a": 3, "b": 4, "c": 5},
|
||||
]
|
||||
)
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`coretutorial_bind_param`
|
||||
|
||||
:ref:`execute_multiple`
|
||||
|
||||
Object Relational Mapping
|
||||
=========================
|
||||
|
||||
.. _error_bhk3:
|
||||
|
||||
Parent instance <x> is not bound to a Session; (lazy load/deferred load/refresh/etc.) operation cannot proceed
|
||||
--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
This is likely the most common error message when dealing with the ORM, and it
|
||||
occurs as a result of the nature of a technique the ORM makes wide use of known
|
||||
as :term:`lazy loading`. Lazy loading is a common object-relational pattern
|
||||
whereby an object that's persisted by the ORM maintains a proxy to the database
|
||||
itself, such that when various attributes upon the object are accessed, their
|
||||
value may be retrieved from the database *lazily*. The advantage to this
|
||||
approach is that objects can be retrieved from the database without having
|
||||
to load all of their attributes or related data at once, and instead only that
|
||||
data which is requested can be delivered at that time. The major disadvantage
|
||||
is basically a mirror image of the advantage, which is that if lots of objects
|
||||
are being loaded which are known to require a certain set of data in all cases,
|
||||
it is wasteful to load that additional data piecemeal.
|
||||
|
||||
Another caveat of lazy loading beyond the usual efficiency concerns is that
|
||||
in order for lazy loading to proceed, the object has to **remain associated
|
||||
with a Session** in order to be able to retrieve its state. This error message
|
||||
means that an object has become de-associated with its :class:`.Session` and
|
||||
is being asked to lazy load data from the database.
|
||||
|
||||
The most common reason that objects become detached from their :class:`.Session`
|
||||
is that the session itself was closed, typically via the :meth:`.Session.close`
|
||||
method. The objects will then live on to be accessed further, very often
|
||||
within web applications where they are delivered to a server-side templating
|
||||
engine and are asked for further attributes which they cannot load.
|
||||
|
||||
Mitigation of this error is via two general techniques:
|
||||
|
||||
* **Don't close the session prematurely** - Often, applications will close
|
||||
out a transaction before passing off related objects to some other system
|
||||
which then fails due to this error. Sometimes the transaction doesn't need
|
||||
to be closed so soon; an example is the web application closes out
|
||||
the transaction before the view is rendered. This is often done in the name
|
||||
of "correctness", but may be seen as a mis-application of "encapsulation",
|
||||
as this term refers to code organization, not actual actions. The template that
|
||||
uses an ORM object is making use of the `proxy pattern <https://en.wikipedia.org/wiki/Proxy_pattern>`_
|
||||
which keeps database logic encapsulated from the caller. If the
|
||||
:class:`.Session` can be held open until the lifespan of the objects are done,
|
||||
this is the best approach.
|
||||
|
||||
* **Load everything that's needed up front** - It is very often impossible to
|
||||
keep the transaction open, especially in more complex applications that need
|
||||
to pass objects off to other systems that can't run in the same context
|
||||
even though they're in the same process. In this case, the application
|
||||
should try to make appropriate use of :term:`eager loading` to ensure
|
||||
that objects have what they need up front. As an additional measure,
|
||||
special directives like the :func:`.raiseload` option can ensure that
|
||||
systems don't call upon lazy loading when its not expected.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`loading_toplevel` - detailed documentation on eager loading and other
|
||||
relationship-oriented loading techniques
|
||||
|
||||
|
||||
Core Exception Classes
|
||||
======================
|
||||
|
||||
See :ref:`core_exceptions_toplevel` for Core exception classes.
|
||||
|
||||
|
||||
ORM Exception Classes
|
||||
======================
|
||||
|
||||
See :ref:`orm_exceptions_toplevel` for ORM exception classes.
|
||||
|
||||
|
||||
|
||||
Vendored
+189
-15
@@ -22,7 +22,7 @@ refers to a :class:`.QueuePool` as a source of connectivity.
|
||||
For more detail, see :ref:`engines_toplevel` and :ref:`pooling_toplevel`.
|
||||
|
||||
How do I pass custom connect arguments to my database API?
|
||||
-----------------------------------------------------------
|
||||
----------------------------------------------------------
|
||||
|
||||
The :func:`.create_engine` call accepts additional arguments either
|
||||
directly via the ``connect_args`` keyword argument::
|
||||
@@ -42,28 +42,121 @@ in the query string of the URL::
|
||||
"MySQL Server has gone away"
|
||||
----------------------------
|
||||
|
||||
There are two major causes for this error:
|
||||
The primary cause of this error is that the MySQL connection has timed out
|
||||
and has been closed by the server. The MySQL server closes connections
|
||||
which have been idle a period of time which defaults to eight hours.
|
||||
To accommodate this, the immediate setting is to enable the
|
||||
:paramref:`.create_engine.pool_recycle` setting, which will ensure that a
|
||||
connection which is older than a set amount of seconds will be discarded
|
||||
and replaced with a new connection when it is next checked out.
|
||||
|
||||
1. The MySQL client closes connections which have been idle for a set period
|
||||
of time, defaulting to eight hours. This can be avoided by using the ``pool_recycle``
|
||||
setting with :func:`.create_engine`, described at :ref:`mysql_connection_timeouts`.
|
||||
For the more general case of accommodating database restarts and other
|
||||
temporary loss of connectivity due to network issues, connections that
|
||||
are in the pool may be recycled in response to more generalized disconnect
|
||||
detection techniques. The section :ref:`pool_disconnects` provides
|
||||
background on both "pessimistic" (e.g. pre-ping) and "optimistic"
|
||||
(e.g. graceful recovery) techniques. Modern SQLAlchemy tends to favor
|
||||
the "pessimistic" approach.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`pool_disconnects`
|
||||
|
||||
.. _mysql_sync_errors:
|
||||
|
||||
"Commands out of sync; you can't run this command now" / "This result object does not return rows. It has been closed automatically"
|
||||
------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
The MySQL drivers have a fairly wide class of failure modes whereby the state of
|
||||
the connection to the server is in an invalid state. Typically, when the connection
|
||||
is used again, one of these two error messages will occur. The reason is because
|
||||
the state of the server has been changed to one in which the client library
|
||||
does not expect, such that when the client library emits a new statement
|
||||
on the connection, the server does not respond as expected.
|
||||
|
||||
In SQLAlchemy, because database connections are pooled, the issue of the messaging
|
||||
being out of sync on a connection becomes more important, since when an operation
|
||||
fails, if the connection itself is in an unusable state, if it goes back into the
|
||||
connection pool, it will malfunction when checked out again. The mitigation
|
||||
for this issue is that the connection is **invalidated** when such a failure
|
||||
mode occurs so that the underlying database connection to MySQL is discarded.
|
||||
This invalidation occurs automatically for many known failure modes and can
|
||||
also be called explicitly via the :meth:`.Connection.invalidate` method.
|
||||
|
||||
There is also a second class of failure modes within this category where a context manager
|
||||
such as ``with session.begin_nested():`` wants to "roll back" the transaction
|
||||
when an error occurs; however within some failure modes of the connection, the
|
||||
rollback itself (which can also be a RELEASE SAVEPOINT operation) also
|
||||
fails, causing misleading stack traces.
|
||||
|
||||
Originally, the cause of this error used to be fairly simple, it meant that
|
||||
a multithreaded program was invoking commands on a single connection from more
|
||||
than one thread. This applied to the original "MySQLdb" native-C driver that was
|
||||
pretty much the only driver in use. However, with the introduction of pure Python
|
||||
drivers like PyMySQL and MySQL-connector-Python, as well as increased use of
|
||||
tools such as gevent/eventlet, multiprocessing (often with Celery), and others,
|
||||
there is a whole series of factors that has been known to cause this problem, some of
|
||||
which have been improved across SQLAlchemy versions but others which are unavoidable:
|
||||
|
||||
* **Sharing a connection among threads** - This is the original reason these kinds
|
||||
of errors occurred. A program used the same connection in two or more threads at
|
||||
the same time, meaning multiple sets of messages got mixed up on the connection,
|
||||
putting the server-side session into a state that the client no longer knows how
|
||||
to interpret. However, other causes are usually more likely today.
|
||||
|
||||
* **Sharing the filehandle for the connection among processes** - This usually occurs
|
||||
when a program uses ``os.fork()`` to spawn a new process, and a TCP connection
|
||||
that is present in th parent process gets shared into one or more child processes.
|
||||
As multiple processes are now emitting messages to essentially the same filehandle,
|
||||
the server receives interleaved messages and breaks the state of the connection.
|
||||
|
||||
This scenario can occur very easily if a program uses Python's "multiprocessing"
|
||||
module and makes use of an :class:`.Engine` that was created in the parent
|
||||
process. It's common that "multiprocessing" is in use when using tools like
|
||||
Celery. The correct approach should be either that a new :class:`.Engine`
|
||||
is produced when a child process first starts, discarding any :class:`.Engine`
|
||||
that came down from the parent process; or, the :class:`.Engine` that's inherited
|
||||
from the parent process can have it's internal pool of connections disposed by
|
||||
calling :meth:`.Engine.dispose`.
|
||||
|
||||
* **Greenlet Monkeypatching w/ Exits** - When using a library like gevent or eventlet
|
||||
that monkeypatches the Python networking API, libraries like PyMySQL are now
|
||||
working in an asynchronous mode of operation, even though they are not developed
|
||||
explicitly against this model. A common issue is that a greenthread is interrupted,
|
||||
often due to timeout logic in the application. This results in the ``GreenletExit``
|
||||
exception being raised, and the pure-Python MySQL driver is interrupted from
|
||||
its work, which may have been that it was receiving a response from the server
|
||||
or preparing to otherwise reset the state of the connection. When the exception
|
||||
cuts all that work short, the conversation between client and server is now
|
||||
out of sync and subsequent usage of the connection may fail. SQLAlchemy
|
||||
as of version 1.1.0 knows how to guard against this, as if a database operation
|
||||
is interrupted by a so-called "exit exception", which includes ``GreenletExit``
|
||||
and any other subclass of Python ``BaseException`` that is not also a subclass
|
||||
of ``Exception``, the connection is invalidated.
|
||||
|
||||
* **Rollbacks / SAVEPOINT releases failing** - Some classes of error cause
|
||||
the connection to be unusable within the context of a transaction, as well
|
||||
as when operating in a "SAVEPOINT" block. In these cases, the failure
|
||||
on the connection has rendered any SAVEPOINT as no longer existing, yet
|
||||
when SQLAlchemy, or the application, attempts to "roll back" this savepoint,
|
||||
the "RELEASE SAVEPOINT" operation fails, typically with a message like
|
||||
"savepoint does not exist". In this case, under Python 3 there will be
|
||||
a chain of exceptions output, where the ultimate "cause" of the error
|
||||
will be displayed as well. Under Python 2, there are no "chained" exceptions,
|
||||
however recent versions of SQLAlchemy will attempt to emit a warning
|
||||
illustrating the original failure cause, while still throwing the
|
||||
immediate error which is the failure of the ROLLBACK.
|
||||
|
||||
2. Usage of the MySQLdb :term:`DBAPI`, or a similar DBAPI, in a non-threadsafe manner, or in an otherwise
|
||||
inappropriate way. The MySQLdb connection object is not threadsafe - this expands
|
||||
out to any SQLAlchemy system that links to a single connection, which includes the ORM
|
||||
:class:`.Session`. For background
|
||||
on how :class:`.Session` should be used in a multithreaded environment,
|
||||
see :ref:`session_faq_threadsafe`.
|
||||
|
||||
Why does SQLAlchemy issue so many ROLLBACKs?
|
||||
---------------------------------------------
|
||||
--------------------------------------------
|
||||
|
||||
SQLAlchemy currently assumes DBAPI connections are in "non-autocommit" mode -
|
||||
this is the default behavior of the Python database API, meaning it
|
||||
must be assumed that a transaction is always in progress. The
|
||||
connection pool issues ``connection.rollback()`` when a connection is returned.
|
||||
This is so that any transactional resources remaining on the connection are
|
||||
released. On a database like Postgresql or MSSQL where table resources are
|
||||
released. On a database like PostgreSQL or MSSQL where table resources are
|
||||
aggressively locked, this is critical so that rows and tables don't remain
|
||||
locked within connections that are no longer in use. An application can
|
||||
otherwise hang. It's not just for locks, however, and is equally critical on
|
||||
@@ -74,7 +167,7 @@ isolation. For background on why you might see stale data even on MySQL, see
|
||||
http://dev.mysql.com/doc/refman/5.1/en/innodb-transaction-model.html
|
||||
|
||||
I'm on MyISAM - how do I turn it off?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The behavior of the connection pool's connection return behavior can be
|
||||
configured using ``reset_on_return``::
|
||||
@@ -85,7 +178,7 @@ configured using ``reset_on_return``::
|
||||
engine = create_engine('mysql://scott:tiger@localhost/myisam_database', pool=QueuePool(reset_on_return=False))
|
||||
|
||||
I'm on SQL Server - how do I turn those ROLLBACKs into COMMITs?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
``reset_on_return`` accepts the values ``commit``, ``rollback`` in addition
|
||||
to ``True``, ``False``, and ``None``. Setting to ``commit`` will cause
|
||||
@@ -136,3 +229,84 @@ when :meth:`.Connection.close` is called::
|
||||
conn.detach() # detaches the DBAPI connection from the connection pool
|
||||
conn.connection.<go nuts>
|
||||
conn.close() # connection is closed for real, the pool replaces it with a new connection
|
||||
|
||||
How do I use engines / connections / sessions with Python multiprocessing, or os.fork()?
|
||||
----------------------------------------------------------------------------------------
|
||||
|
||||
The key goal with multiple python processes is to prevent any database connections
|
||||
from being shared across processes. Depending on specifics of the driver and OS,
|
||||
the issues that arise here range from non-working connections to socket connections that
|
||||
are used by multiple processes concurrently, leading to broken messaging (the latter
|
||||
case is typically the most common).
|
||||
|
||||
The SQLAlchemy :class:`.Engine` object refers to a connection pool of existing
|
||||
database connections. So when this object is replicated to a child process,
|
||||
the goal is to ensure that no database connections are carried over. There
|
||||
are three general approaches to this:
|
||||
|
||||
1. Disable pooling using :class:`.NullPool`. This is the most simplistic,
|
||||
one shot system that prevents the :class:`.Engine` from using any connection
|
||||
more than once.
|
||||
|
||||
2. Call :meth:`.Engine.dispose` on any given :class:`.Engine` as soon one is
|
||||
within the new process. In Python multiprocessing, constructs such as
|
||||
``multiprocessing.Pool`` include "initializer" hooks which are a place
|
||||
that this can be performed; otherwise at the top of where ``os.fork()``
|
||||
or where the ``Process`` object begins the child fork, a single call
|
||||
to :meth:`.Engine.dispose` will ensure any remaining connections are flushed.
|
||||
|
||||
3. An event handler can be applied to the connection pool that tests for connections
|
||||
being shared across process boundaries, and invalidates them. This looks like
|
||||
the following::
|
||||
|
||||
import os
|
||||
import warnings
|
||||
|
||||
from sqlalchemy import event
|
||||
from sqlalchemy import exc
|
||||
|
||||
def add_engine_pidguard(engine):
|
||||
"""Add multiprocessing guards.
|
||||
|
||||
Forces a connection to be reconnected if it is detected
|
||||
as having been shared to a sub-process.
|
||||
|
||||
"""
|
||||
|
||||
@event.listens_for(engine, "connect")
|
||||
def connect(dbapi_connection, connection_record):
|
||||
connection_record.info['pid'] = os.getpid()
|
||||
|
||||
@event.listens_for(engine, "checkout")
|
||||
def checkout(dbapi_connection, connection_record, connection_proxy):
|
||||
pid = os.getpid()
|
||||
if connection_record.info['pid'] != pid:
|
||||
# substitute log.debug() or similar here as desired
|
||||
warnings.warn(
|
||||
"Parent process %(orig)s forked (%(newproc)s) with an open "
|
||||
"database connection, "
|
||||
"which is being discarded and recreated." %
|
||||
{"newproc": pid, "orig": connection_record.info['pid']})
|
||||
connection_record.connection = connection_proxy.connection = None
|
||||
raise exc.DisconnectionError(
|
||||
"Connection record belongs to pid %s, "
|
||||
"attempting to check out in pid %s" %
|
||||
(connection_record.info['pid'], pid)
|
||||
)
|
||||
|
||||
These events are applied to an :class:`.Engine` as soon as its created::
|
||||
|
||||
engine = create_engine("...")
|
||||
|
||||
add_engine_pidguard(engine)
|
||||
|
||||
The above strategies will accommodate the case of an :class:`.Engine`
|
||||
being shared among processes. However, for the case of a transaction-active
|
||||
:class:`.Session` or :class:`.Connection` being shared, there's no automatic
|
||||
fix for this; an application needs to ensure a new child process only
|
||||
initiate new :class:`.Connection` objects and transactions, as well as ORM
|
||||
:class:`.Session` objects. For a :class:`.Session` object, technically
|
||||
this is only needed if the session is currently transaction-bound, however
|
||||
the scope of a single :class:`.Session` is in any case intended to be
|
||||
kept within a single call stack in any case (e.g. not a global object, not
|
||||
shared between processes or threads).
|
||||
|
||||
Vendored
+2
-2
@@ -1,8 +1,8 @@
|
||||
.. _faq_toplevel:
|
||||
|
||||
============================
|
||||
==========================
|
||||
Frequently Asked Questions
|
||||
============================
|
||||
==========================
|
||||
|
||||
The Frequently Asked Questions section is a growing collection of commonly
|
||||
observed questions to well-known issues.
|
||||
|
||||
Vendored
+10
-10
@@ -1,6 +1,6 @@
|
||||
==================
|
||||
=================
|
||||
MetaData / Schema
|
||||
==================
|
||||
=================
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
@@ -56,7 +56,7 @@ A more comprehensive option is to use schema migration tools, such as Alembic
|
||||
or SQLAlchemy-Migrate; see :ref:`schema_migrations` for discussion on this.
|
||||
|
||||
How can I sort Table objects in order of their dependency?
|
||||
===========================================================================
|
||||
==========================================================
|
||||
|
||||
This is available via the :attr:`.MetaData.sorted_tables` function::
|
||||
|
||||
@@ -64,35 +64,35 @@ This is available via the :attr:`.MetaData.sorted_tables` function::
|
||||
# ... add Table objects to metadata
|
||||
ti = metadata.sorted_tables:
|
||||
for t in ti:
|
||||
print t
|
||||
print(t)
|
||||
|
||||
How can I get the CREATE TABLE/ DROP TABLE output as a string?
|
||||
===========================================================================
|
||||
==============================================================
|
||||
|
||||
Modern SQLAlchemy has clause constructs which represent DDL operations. These
|
||||
can be rendered to strings like any other SQL expression::
|
||||
|
||||
from sqlalchemy.schema import CreateTable
|
||||
|
||||
print CreateTable(mytable)
|
||||
print(CreateTable(mytable))
|
||||
|
||||
To get the string specific to a certain engine::
|
||||
|
||||
print CreateTable(mytable).compile(engine)
|
||||
print(CreateTable(mytable).compile(engine))
|
||||
|
||||
There's also a special form of :class:`.Engine` that can let you dump an entire
|
||||
metadata creation sequence, using this recipe::
|
||||
|
||||
def dump(sql, *multiparams, **params):
|
||||
print sql.compile(dialect=engine.dialect)
|
||||
print(sql.compile(dialect=engine.dialect))
|
||||
engine = create_engine('postgresql://', strategy='mock', executor=dump)
|
||||
metadata.create_all(engine, checkfirst=False)
|
||||
|
||||
The `Alembic <https://bitbucket.org/zzzeek/alembic>`_ tool also supports
|
||||
The `Alembic <https://alembic.sqlalchemy.org>`_ tool also supports
|
||||
an "offline" SQL generation mode that renders database migrations as SQL scripts.
|
||||
|
||||
How can I subclass Table/Column to provide certain behaviors/configurations?
|
||||
=============================================================================
|
||||
============================================================================
|
||||
|
||||
:class:`.Table` and :class:`.Column` are not good targets for direct subclassing.
|
||||
However, there are simple ways to get on-construction behaviors using creation
|
||||
|
||||
Vendored
+10
-7
@@ -1,5 +1,5 @@
|
||||
ORM Configuration
|
||||
==================
|
||||
=================
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
@@ -72,7 +72,7 @@ columns::
|
||||
|
||||
|
||||
How do I configure a Column that is a Python reserved word or similar?
|
||||
----------------------------------------------------------------------------
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Column-based attributes can be given any name desired in the mapping. See
|
||||
:ref:`mapper_column_distinct_names`.
|
||||
@@ -89,7 +89,8 @@ To get at the :class:`.Mapper` for a particular mapped class, call the
|
||||
|
||||
mapper = inspect(MyClass)
|
||||
|
||||
From there, all information about the class can be acquired using such methods as:
|
||||
From there, all information about the class can be accessed through properties
|
||||
such as:
|
||||
|
||||
* :attr:`.Mapper.attrs` - a namespace of all mapped attributes. The attributes
|
||||
themselves are instances of :class:`.MapperProperty`, which contain additional
|
||||
@@ -293,7 +294,7 @@ the two queries may not see the same results:
|
||||
ORDER BY anon_1.users_id
|
||||
|
||||
Depending on database specifics, there is
|
||||
a chance we may get the a result like the following for the two queries::
|
||||
a chance we may get a result like the following for the two queries::
|
||||
|
||||
-- query #1
|
||||
+--------+
|
||||
@@ -325,9 +326,11 @@ The primary key is a good choice for this::
|
||||
|
||||
session.query(User).options(subqueryload(User.addresses)).order_by(User.id).first()
|
||||
|
||||
Note that :func:`.joinedload` does not suffer from the same problem because
|
||||
only one query is ever issued, so the load query cannot be different from the
|
||||
main query.
|
||||
Note that the :func:`.joinedload` eager loader strategy does not suffer from
|
||||
the same problem because only one query is ever issued, so the load query
|
||||
cannot be different from the main query. Similarly, the :func:`.selectinload`
|
||||
eager loader strategy also does not have this issue as it links its collection
|
||||
loads directly to primary key values just loaded.
|
||||
|
||||
.. seealso::
|
||||
|
||||
|
||||
Vendored
+51
-28
@@ -13,11 +13,11 @@ Performance
|
||||
How can I profile a SQLAlchemy powered application?
|
||||
---------------------------------------------------
|
||||
|
||||
Looking for performance issues typically involves two stratgies. One
|
||||
Looking for performance issues typically involves two strategies. One
|
||||
is query profiling, and the other is code profiling.
|
||||
|
||||
Query Profiling
|
||||
^^^^^^^^^^^^^^^^
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Sometimes just plain SQL logging (enabled via python's logging module
|
||||
or via the ``echo=True`` argument on :func:`.create_engine`) can give an
|
||||
@@ -104,7 +104,7 @@ Below is a simple recipe which works profiling into a context manager::
|
||||
ps.print_stats()
|
||||
# uncomment this to see who's calling what
|
||||
# ps.print_callers()
|
||||
print s.getvalue()
|
||||
print(s.getvalue())
|
||||
|
||||
To profile a section of code::
|
||||
|
||||
@@ -154,7 +154,7 @@ analysis of the query plan is warranted, using a system such as EXPLAIN,
|
||||
SHOW PLAN, etc. as is provided by the database backend.
|
||||
|
||||
Result Fetching Slowness - Core
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If on the other hand you see many thousands of calls related to fetching rows,
|
||||
or very long calls to ``fetchall()``, it may
|
||||
@@ -223,7 +223,7 @@ that could indicate that everything is fast except for the actual network connec
|
||||
and too much time is spent with data moving over the network.
|
||||
|
||||
Result Fetching Slowness - ORM
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To detect slowness in ORM fetching of rows (which is the most common area
|
||||
of performance concern), calls like ``populate_state()`` and ``_instance()`` will
|
||||
@@ -258,7 +258,7 @@ Common strategies to mitigate this include:
|
||||
* Use result caching - see :ref:`examples_caching` for an in-depth example
|
||||
of this.
|
||||
|
||||
* Consider a faster interpreter like that of Pypy.
|
||||
* Consider a faster interpreter like that of PyPy.
|
||||
|
||||
The output of a profile can be a little daunting but after some
|
||||
practice they are very easy to read.
|
||||
@@ -269,7 +269,7 @@ practice they are very easy to read.
|
||||
with bundled profiling capabilities.
|
||||
|
||||
I'm inserting 400,000 rows with the ORM and it's really slow!
|
||||
--------------------------------------------------------------
|
||||
-------------------------------------------------------------
|
||||
|
||||
The SQLAlchemy ORM uses the :term:`unit of work` pattern when synchronizing
|
||||
changes to the database. This pattern goes far beyond simple "inserts"
|
||||
@@ -298,6 +298,12 @@ SQL generation and execution system that the ORM builds on top of
|
||||
is part of the :doc:`Core <core/tutorial>`. Using this system directly, we can produce an INSERT that
|
||||
is competitive with using the raw database API directly.
|
||||
|
||||
.. note::
|
||||
|
||||
When using the psycopg2 dialect, consider making use of the
|
||||
:ref:`batch execution helpers <psycopg2_batch_mode>` feature of psycopg2,
|
||||
now supported directly by the SQLAlchemy psycopg2 dialect.
|
||||
|
||||
Alternatively, the SQLAlchemy ORM offers the :ref:`bulk_operations`
|
||||
suite of methods, which provide hooks into subsections of the unit of
|
||||
work process in order to emit Core-level INSERT and UPDATE constructs with
|
||||
@@ -307,20 +313,21 @@ The example below illustrates time-based tests for several different
|
||||
methods of inserting rows, going from the most automated to the least.
|
||||
With cPython 2.7, runtimes observed::
|
||||
|
||||
classics-MacBook-Pro:sqlalchemy classic$ python test.py
|
||||
SQLAlchemy ORM: Total time for 100000 records 12.0471920967 secs
|
||||
SQLAlchemy ORM pk given: Total time for 100000 records 7.06283402443 secs
|
||||
SQLAlchemy ORM bulk_save_objects(): Total time for 100000 records 0.856323003769 secs
|
||||
SQLAlchemy Core: Total time for 100000 records 0.485800027847 secs
|
||||
sqlite3: Total time for 100000 records 0.487842082977 sec
|
||||
SQLAlchemy ORM: Total time for 100000 records 6.89754080772 secs
|
||||
SQLAlchemy ORM pk given: Total time for 100000 records 4.09481811523 secs
|
||||
SQLAlchemy ORM bulk_save_objects(): Total time for 100000 records 1.65821218491 secs
|
||||
SQLAlchemy ORM bulk_insert_mappings(): Total time for 100000 records 0.466513156891 secs
|
||||
SQLAlchemy Core: Total time for 100000 records 0.21024107933 secs
|
||||
sqlite3: Total time for 100000 records 0.137335062027 sec
|
||||
|
||||
We can reduce the time by a factor of three using recent versions of `Pypy <http://pypy.org/>`_::
|
||||
We can reduce the time by a factor of nearly three using recent versions of `PyPy <http://pypy.org/>`_::
|
||||
|
||||
classics-MacBook-Pro:sqlalchemy classic$ /usr/local/src/pypy-2.1-beta2-osx64/bin/pypy test.py
|
||||
SQLAlchemy ORM: Total time for 100000 records 5.88369488716 secs
|
||||
SQLAlchemy ORM pk given: Total time for 100000 records 3.52294301987 secs
|
||||
SQLAlchemy Core: Total time for 100000 records 0.613556146622 secs
|
||||
sqlite3: Total time for 100000 records 0.442467927933 sec
|
||||
SQLAlchemy ORM: Total time for 100000 records 2.39429616928 secs
|
||||
SQLAlchemy ORM pk given: Total time for 100000 records 1.51412987709 secs
|
||||
SQLAlchemy ORM bulk_save_objects(): Total time for 100000 records 0.568987131119 secs
|
||||
SQLAlchemy ORM bulk_insert_mappings(): Total time for 100000 records 0.320806980133 secs
|
||||
SQLAlchemy Core: Total time for 100000 records 0.206904888153 secs
|
||||
sqlite3: Total time for 100000 records 0.165791988373 sec
|
||||
|
||||
Script::
|
||||
|
||||
@@ -370,7 +377,7 @@ Script::
|
||||
init_sqlalchemy()
|
||||
t0 = time.time()
|
||||
for i in xrange(n):
|
||||
customer = Customer(id=i+1, name="NAME " + str(i))
|
||||
customer = Customer(id=i + 1, name="NAME " + str(i))
|
||||
DBSession.add(customer)
|
||||
if i % 1000 == 0:
|
||||
DBSession.flush()
|
||||
@@ -380,17 +387,14 @@ Script::
|
||||
" records " + str(time.time() - t0) + " secs")
|
||||
|
||||
|
||||
def test_sqlalchemy_orm_bulk_insert(n=100000):
|
||||
def test_sqlalchemy_orm_bulk_save_objects(n=100000):
|
||||
init_sqlalchemy()
|
||||
t0 = time.time()
|
||||
n1 = n
|
||||
while n1 > 0:
|
||||
n1 = n1 - 10000
|
||||
DBSession.bulk_insert_mappings(
|
||||
Customer,
|
||||
for chunk in range(0, n, 10000):
|
||||
DBSession.bulk_save_objects(
|
||||
[
|
||||
dict(name="NAME " + str(i))
|
||||
for i in xrange(min(10000, n1))
|
||||
Customer(name="NAME " + str(i))
|
||||
for i in xrange(chunk, min(chunk + 10000, n))
|
||||
]
|
||||
)
|
||||
DBSession.commit()
|
||||
@@ -399,6 +403,23 @@ Script::
|
||||
" records " + str(time.time() - t0) + " secs")
|
||||
|
||||
|
||||
def test_sqlalchemy_orm_bulk_insert(n=100000):
|
||||
init_sqlalchemy()
|
||||
t0 = time.time()
|
||||
for chunk in range(0, n, 10000):
|
||||
DBSession.bulk_insert_mappings(
|
||||
Customer,
|
||||
[
|
||||
dict(name="NAME " + str(i))
|
||||
for i in xrange(chunk, min(chunk + 10000, n))
|
||||
]
|
||||
)
|
||||
DBSession.commit()
|
||||
print(
|
||||
"SQLAlchemy ORM bulk_insert_mappings(): Total time for " + str(n) +
|
||||
" records " + str(time.time() - t0) + " secs")
|
||||
|
||||
|
||||
def test_sqlalchemy_core(n=100000):
|
||||
init_sqlalchemy()
|
||||
t0 = time.time()
|
||||
@@ -437,7 +458,9 @@ Script::
|
||||
if __name__ == '__main__':
|
||||
test_sqlalchemy_orm(100000)
|
||||
test_sqlalchemy_orm_pk_given(100000)
|
||||
test_sqlalchemy_orm_bulk_save_objects(100000)
|
||||
test_sqlalchemy_orm_bulk_insert(100000)
|
||||
test_sqlalchemy_core(100000)
|
||||
test_sqlite3(100000)
|
||||
|
||||
|
||||
|
||||
Vendored
+107
-8
@@ -1,5 +1,5 @@
|
||||
Sessions / Queries
|
||||
===================
|
||||
==================
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
@@ -135,7 +135,7 @@ For a detailed discussion on how to organize usage of the :class:`.Session`,
|
||||
please see :ref:`session_faq_whentocreate`.
|
||||
|
||||
But why does flush() insist on issuing a ROLLBACK?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
It would be great if :meth:`.Session.flush` could partially complete and then not roll
|
||||
back, however this is beyond its current capabilities since its internal
|
||||
@@ -268,7 +268,7 @@ The joins generated by joined eager loading are only used to fully load related
|
||||
collections, and are designed to have no impact on the primary results of the query.
|
||||
Since they are anonymously aliased, they cannot be referenced directly.
|
||||
|
||||
For detail on this beahvior, see :doc:`orm/loading`.
|
||||
For detail on this behavior, see :ref:`zen_of_eager_loading`.
|
||||
|
||||
Query has no ``__len__()``, why not?
|
||||
------------------------------------
|
||||
@@ -282,11 +282,11 @@ one::
|
||||
|
||||
class Iterates(object):
|
||||
def __len__(self):
|
||||
print "LEN!"
|
||||
print("LEN!")
|
||||
return 5
|
||||
|
||||
def __iter__(self):
|
||||
print "ITER!"
|
||||
print("ITER!")
|
||||
return iter([1, 2, 3, 4, 5])
|
||||
|
||||
list(Iterates())
|
||||
@@ -297,7 +297,7 @@ output::
|
||||
LEN!
|
||||
|
||||
How Do I use Textual SQL with ORM Queries?
|
||||
-------------------------------------------
|
||||
------------------------------------------
|
||||
|
||||
See:
|
||||
|
||||
@@ -316,12 +316,12 @@ why isn't my ``__init__()`` called when I load objects?
|
||||
See :ref:`mapping_constructors` for a description of this behavior.
|
||||
|
||||
how do I use ON DELETE CASCADE with SA's ORM?
|
||||
----------------------------------------------
|
||||
---------------------------------------------
|
||||
|
||||
SQLAlchemy will always issue UPDATE or DELETE statements for dependent
|
||||
rows which are currently loaded in the :class:`.Session`. For rows which
|
||||
are not loaded, it will by default issue SELECT statements to load
|
||||
those rows and udpate/delete those as well; in other words it assumes
|
||||
those rows and update/delete those as well; in other words it assumes
|
||||
there is no ON DELETE CASCADE configured.
|
||||
To configure SQLAlchemy to cooperate with ON DELETE CASCADE, see
|
||||
:ref:`passive_deletes`.
|
||||
@@ -417,6 +417,77 @@ The recipe `ExpireRelationshipOnFKChange <http://www.sqlalchemy.org/trac/wiki/Us
|
||||
in order to coordinate the setting of foreign key attributes with many-to-one
|
||||
relationships.
|
||||
|
||||
.. _faq_walk_objects:
|
||||
|
||||
How do I walk all objects that are related to a given object?
|
||||
-------------------------------------------------------------
|
||||
|
||||
An object that has other objects related to it will correspond to the
|
||||
:func:`.relationship` constructs set up between mappers. This code fragment will
|
||||
iterate all the objects, correcting for cycles as well::
|
||||
|
||||
from sqlalchemy import inspect
|
||||
|
||||
|
||||
def walk(obj):
|
||||
deque = [obj]
|
||||
|
||||
seen = set()
|
||||
|
||||
while deque:
|
||||
obj = deque.pop(0)
|
||||
if obj in seen:
|
||||
continue
|
||||
else:
|
||||
seen.add(obj)
|
||||
yield obj
|
||||
insp = inspect(obj)
|
||||
for relationship in insp.mapper.relationships:
|
||||
related = getattr(obj, relationship.key)
|
||||
if relationship.uselist:
|
||||
deque.extend(related)
|
||||
elif related is not None:
|
||||
deque.append(related)
|
||||
|
||||
The function can be demonstrated as follows::
|
||||
|
||||
Base = declarative_base()
|
||||
|
||||
|
||||
class A(Base):
|
||||
__tablename__ = 'a'
|
||||
id = Column(Integer, primary_key=True)
|
||||
bs = relationship("B", backref="a")
|
||||
|
||||
|
||||
class B(Base):
|
||||
__tablename__ = 'b'
|
||||
id = Column(Integer, primary_key=True)
|
||||
a_id = Column(ForeignKey('a.id'))
|
||||
c_id = Column(ForeignKey('c.id'))
|
||||
c = relationship("C", backref="bs")
|
||||
|
||||
|
||||
class C(Base):
|
||||
__tablename__ = 'c'
|
||||
id = Column(Integer, primary_key=True)
|
||||
|
||||
|
||||
a1 = A(bs=[B(), B(c=C())])
|
||||
|
||||
|
||||
for obj in walk(a1):
|
||||
print(obj)
|
||||
|
||||
Output::
|
||||
|
||||
<__main__.A object at 0x10303b190>
|
||||
<__main__.B object at 0x103025210>
|
||||
<__main__.B object at 0x10303b0d0>
|
||||
<__main__.C object at 0x103025490>
|
||||
|
||||
|
||||
|
||||
Is there a way to automagically have only unique keywords (or other kinds of objects) without doing a query for the keyword and getting a reference to the row containing that keyword?
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -426,4 +497,32 @@ Which is somewhat inconvenient.
|
||||
|
||||
This `UniqueObject <http://www.sqlalchemy.org/trac/wiki/UsageRecipes/UniqueObject>`_ recipe was created to address this issue.
|
||||
|
||||
.. _faq_post_update_update:
|
||||
|
||||
Why does post_update emit UPDATE in addition to the first UPDATE?
|
||||
-----------------------------------------------------------------
|
||||
|
||||
The post_update feature, documented at :ref:`post_update`, involves that an
|
||||
UPDATE statement is emitted in response to changes to a particular
|
||||
relationship-bound foreign key, in addition to the INSERT/UPDATE/DELETE that
|
||||
would normally be emitted for the target row. While the primary purpose of this
|
||||
UPDATE statement is that it pairs up with an INSERT or DELETE of that row, so
|
||||
that it can post-set or pre-unset a foreign key reference in order to break a
|
||||
cycle with a mutually dependent foreign key, it currently is also bundled as a
|
||||
second UPDATE that emits when the target row itself is subject to an UPDATE.
|
||||
In this case, the UPDATE emitted by post_update is *usually* unnecessary
|
||||
and will often appear wasteful.
|
||||
|
||||
However, some research into trying to remove this "UPDATE / UPDATE" behavior
|
||||
reveals that major changes to the unit of work process would need to occur not
|
||||
just throughout the post_update implementation, but also in areas that aren't
|
||||
related to post_update for this to work, in that the order of operations would
|
||||
need to be reversed on the non-post_update side in some cases, which in turn
|
||||
can impact other cases, such as correctly handling an UPDATE of a referenced
|
||||
primary key value (see :ticket:`1063` for a proof of concept).
|
||||
|
||||
The answer is that "post_update" is used to break a cycle between two
|
||||
mutually dependent foreign keys, and to have this cycle breaking be limited
|
||||
to just INSERT/DELETE of the target table implies that the ordering of UPDATE
|
||||
statements elsewhere would need to be liberalized, leading to breakage
|
||||
in other edge cases.
|
||||
|
||||
Vendored
+79
-34
@@ -1,5 +1,5 @@
|
||||
SQL Expressions
|
||||
=================
|
||||
===============
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
@@ -88,53 +88,98 @@ producing output like::
|
||||
WHERE mytable.x > my_fancy_formatting(5)
|
||||
|
||||
|
||||
Why does ``.col.in_([])`` Produce ``col != col``? Why not ``1=0``?
|
||||
-------------------------------------------------------------------
|
||||
.. _faq_sql_expression_op_parenthesis:
|
||||
|
||||
A little introduction to the issue. The IN operator in SQL, given a list of
|
||||
elements to compare against a column, generally does not accept an empty list,
|
||||
that is while it is valid to say::
|
||||
I'm using op() to generate a custom operator and my parenthesis are not coming out correctly
|
||||
---------------------------------------------------------------------------------------------
|
||||
|
||||
column IN (1, 2, 3)
|
||||
The :meth:`.Operators.op` method allows one to create a custom database operator
|
||||
otherwise not known by SQLAlchemy::
|
||||
|
||||
it's not valid to say::
|
||||
>>> print(column('q').op('->')(column('p')))
|
||||
q -> p
|
||||
|
||||
column IN ()
|
||||
However, when using it on the right side of a compound expression, it doesn't
|
||||
generate parenthesis as we expect::
|
||||
|
||||
SQLAlchemy's :meth:`.Operators.in_` operator, when given an empty list, produces this
|
||||
expression::
|
||||
>>> print((column('q1') + column('q2')).op('->')(column('p')))
|
||||
q1 + q2 -> p
|
||||
|
||||
column != column
|
||||
Where above, we probably want ``(q1 + q2) -> p``.
|
||||
|
||||
As of version 0.6, it also produces a warning stating that a less efficient
|
||||
comparison operation will be rendered. This expression is the only one that is
|
||||
both database agnostic and produces correct results.
|
||||
The solution to this case is to set the precedence of the operator, using
|
||||
the :paramref:`.Operators.op.precedence` parameter, to a high
|
||||
number, where 100 is the maximum value, and the highest number used by any
|
||||
SQLAlchemy operator is currently 15::
|
||||
|
||||
For example, the naive approach of "just evaluate to false, by comparing 1=0
|
||||
or 1!=1", does not handle nulls properly. An expression like::
|
||||
>>> print((column('q1') + column('q2')).op('->', precedence=100)(column('p')))
|
||||
(q1 + q2) -> p
|
||||
|
||||
NOT column != column
|
||||
We can also usually force parenthesization around a binary expression (e.g.
|
||||
an expression that has left/right operands and an operator) using the
|
||||
:meth:`.ColumnElement.self_group` method::
|
||||
|
||||
will not return a row when "column" is null, but an expression which does not
|
||||
take the column into account::
|
||||
>>> print((column('q1') + column('q2')).self_group().op('->')(column('p')))
|
||||
(q1 + q2) -> p
|
||||
|
||||
NOT 1=0
|
||||
Why are the parentheses rules like this?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
will.
|
||||
A lot of databases barf when there are excessive parenthesis or when
|
||||
parenthesis are in unusual places they doesn't expect, so SQLAlchemy does not
|
||||
generate parenthesis based on groupings, it uses operator precedence and if the
|
||||
operator is known to be associative, so that parenthesis are generated
|
||||
minimally. Otherwise, an expression like::
|
||||
|
||||
Closer to the mark is the following CASE expression::
|
||||
column('a') & column('b') & column('c') & column('d')
|
||||
|
||||
CASE WHEN column IS NOT NULL THEN 1=0 ELSE NULL END
|
||||
would produce::
|
||||
|
||||
We don't use this expression due to its verbosity, and its also not
|
||||
typically accepted by Oracle within a WHERE clause - depending
|
||||
on how you phrase it, you'll either get "ORA-00905: missing keyword" or
|
||||
"ORA-00920: invalid relational operator". It's also still less efficient than
|
||||
just rendering SQL without the clause altogether (or not issuing the SQL at
|
||||
all, if the statement is just a simple search).
|
||||
(((a AND b) AND c) AND d)
|
||||
|
||||
The best approach therefore is to avoid the usage of IN given an argument list
|
||||
of zero length. Instead, don't emit the Query in the first place, if no rows
|
||||
should be returned. The warning is best promoted to a full error condition
|
||||
using the Python warnings filter (see http://docs.python.org/library/warnings.html).
|
||||
which is fine but would probably annoy people (and be reported as a bug). In
|
||||
other cases, it leads to things that are more likely to confuse databases or at
|
||||
the very least readability, such as::
|
||||
|
||||
column('q', ARRAY(Integer, dimensions=2))[5][6]
|
||||
|
||||
would produce::
|
||||
|
||||
((q[5])[6])
|
||||
|
||||
There are also some edge cases where we get things like ``"(x) = 7"`` and databases
|
||||
really don't like that either. So parenthesization doesn't naively
|
||||
parenthesize, it uses operator precedence and associativity to determine
|
||||
groupings.
|
||||
|
||||
For :meth:`.Operators.op`, the value of precedence defaults to zero.
|
||||
|
||||
What if we defaulted the value of :paramref:`.Operators.op.precedence` to 100,
|
||||
e.g. the highest? Then this expression makes more parenthesis, but is
|
||||
otherwise OK, that is, these two are equivalent::
|
||||
|
||||
>>> print (column('q') - column('y')).op('+', precedence=100)(column('z'))
|
||||
(q - y) + z
|
||||
>>> print (column('q') - column('y')).op('+')(column('z'))
|
||||
q - y + z
|
||||
|
||||
but these two are not::
|
||||
|
||||
>>> print column('q') - column('y').op('+', precedence=100)(column('z'))
|
||||
q - y + z
|
||||
>>> print column('q') - column('y').op('+')(column('z'))
|
||||
q - (y + z)
|
||||
|
||||
For now, it's not clear that as long as we are doing parenthesization based on
|
||||
operator precedence and associativity, if there is really a way to parenthesize
|
||||
automatically for a generic operator with no precedence given that is going to
|
||||
work in all cases, because sometimes you want a custom op to have a lower
|
||||
precedence than the other operators and sometimes you want it to be higher.
|
||||
|
||||
It is possible that maybe if the "binary" expression above forced the use of
|
||||
the ``self_group()`` method when ``op()`` is called, making the assumption that
|
||||
a compound expression on the left side can always be parenthesized harmlessly.
|
||||
Perhaps this change can be made at some point, however for the time being
|
||||
keeping the parenthesization rules more internally consistent seems to be
|
||||
the safer approach.
|
||||
|
||||
|
||||
Vendored
+31
-13
@@ -60,7 +60,7 @@ Glossary
|
||||
``__delete__()`` methods. The :class:`.InstrumentedAttribute`
|
||||
will generate a SQL expression when used at the class level::
|
||||
|
||||
>>> print MyClass.data == 5
|
||||
>>> print(MyClass.data == 5)
|
||||
data = :data_1
|
||||
|
||||
and at the instance level, keeps track of changes to values,
|
||||
@@ -103,7 +103,7 @@ Glossary
|
||||
Instrumentation refers to the process of augmenting the functionality
|
||||
and attribute set of a particular class. Ideally, the
|
||||
behavior of the class should remain close to a regular
|
||||
class, except that additional behviors and features are
|
||||
class, except that additional behaviors and features are
|
||||
made available. The SQLAlchemy :term:`mapping` process,
|
||||
among other things, adds database-enabled :term:`descriptors`
|
||||
to a mapped
|
||||
@@ -129,6 +129,7 @@ Glossary
|
||||
|
||||
lazy load
|
||||
lazy loads
|
||||
lazy loaded
|
||||
lazy loading
|
||||
In object relational mapping, a "lazy load" refers to an
|
||||
attribute that does not contain its database-side value
|
||||
@@ -245,7 +246,7 @@ Glossary
|
||||
transactional resources", to indicate more explicitly that
|
||||
what we are actually "releasing" is any transactional
|
||||
state which as accumulated upon the connection. In most
|
||||
situations, the proces of selecting from tables, emitting
|
||||
situations, the process of selecting from tables, emitting
|
||||
updates, etc. acquires :term:`isolated` state upon
|
||||
that connection as well as potential row or table locks.
|
||||
This state is all local to a particular transaction
|
||||
@@ -359,7 +360,7 @@ Glossary
|
||||
comprises the WHERE clause of the ``SELECT``.
|
||||
|
||||
FROM clause
|
||||
The portion of the ``SELECT`` statement which incicates the initial
|
||||
The portion of the ``SELECT`` statement which indicates the initial
|
||||
source of rows.
|
||||
|
||||
A simple ``SELECT`` will feature one or more table names in its
|
||||
@@ -513,7 +514,7 @@ Glossary
|
||||
http://en.wikipedia.org/wiki/Atomicity_(database_systems)
|
||||
|
||||
consistency
|
||||
Consistency is one of the compoments of the :term:`ACID` model,
|
||||
Consistency is one of the components of the :term:`ACID` model,
|
||||
and ensures that any transaction will
|
||||
bring the database from one valid state to another. Any data
|
||||
written to the database must be valid according to all defined
|
||||
@@ -573,7 +574,7 @@ Glossary
|
||||
were created, as well as a way to get at server-generated
|
||||
default values in an atomic way.
|
||||
|
||||
An example of RETURNING, idiomatic to Postgresql, looks like::
|
||||
An example of RETURNING, idiomatic to PostgreSQL, looks like::
|
||||
|
||||
INSERT INTO user_account (name) VALUES ('new name') RETURNING id, timestamp
|
||||
|
||||
@@ -584,14 +585,14 @@ Glossary
|
||||
or SQL expressions can be placed into RETURNING, not just default-value columns).
|
||||
|
||||
The backends that currently support
|
||||
RETURNING or a similar construct are Postgresql, SQL Server, Oracle,
|
||||
and Firebird. The Postgresql and Firebird implementations are generally
|
||||
RETURNING or a similar construct are PostgreSQL, SQL Server, Oracle,
|
||||
and Firebird. The PostgreSQL and Firebird implementations are generally
|
||||
full featured, whereas the implementations of SQL Server and Oracle
|
||||
have caveats. On SQL Server, the clause is known as "OUTPUT INSERTED"
|
||||
for INSERT and UPDATE statements and "OUTPUT DELETED" for DELETE statements;
|
||||
the key caveat is that triggers are not supported in conjunction with this
|
||||
keyword. On Oracle, it is known as "RETURNING...INTO", and requires that the
|
||||
value be placed into an OUT paramter, meaning not only is the syntax awkward,
|
||||
value be placed into an OUT parameter, meaning not only is the syntax awkward,
|
||||
but it can also only be used for one row at a time.
|
||||
|
||||
SQLAlchemy's :meth:`.UpdateBase.returning` system provides a layer of abstraction
|
||||
@@ -937,6 +938,8 @@ Glossary
|
||||
|
||||
http://en.wikipedia.org/wiki/Candidate_key
|
||||
|
||||
https://www.databasestar.com/database-keys/
|
||||
|
||||
primary key
|
||||
primary key constraint
|
||||
|
||||
@@ -1019,7 +1022,7 @@ Glossary
|
||||
http://en.wikipedia.org/wiki/Unique_key#Defining_unique_keys
|
||||
|
||||
transient
|
||||
This describes one of the four major object states which
|
||||
This describes one of the major object states which
|
||||
an object can have within a :term:`session`; a transient object
|
||||
is a new object that doesn't have any database identity
|
||||
and has not been associated with a session yet. When the
|
||||
@@ -1031,7 +1034,7 @@ Glossary
|
||||
:ref:`session_object_states`
|
||||
|
||||
pending
|
||||
This describes one of the four major object states which
|
||||
This describes one of the major object states which
|
||||
an object can have within a :term:`session`; a pending object
|
||||
is a new object that doesn't have any database identity,
|
||||
but has been recently associated with a session. When
|
||||
@@ -1042,8 +1045,23 @@ Glossary
|
||||
|
||||
:ref:`session_object_states`
|
||||
|
||||
deleted
|
||||
This describes one of the major object states which
|
||||
an object can have within a :term:`session`; a deleted object
|
||||
is an object that was formerly persistent and has had a
|
||||
DELETE statement emitted to the database within a flush
|
||||
to delete its row. The object will move to the :term:`detached`
|
||||
state once the session's transaction is committed; alternatively,
|
||||
if the session's transaction is rolled back, the DELETE is
|
||||
reverted and the object moves back to the :term:`persistent`
|
||||
state.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`session_object_states`
|
||||
|
||||
persistent
|
||||
This describes one of the four major object states which
|
||||
This describes one of the major object states which
|
||||
an object can have within a :term:`session`; a persistent object
|
||||
is an object that has a database identity (i.e. a primary key)
|
||||
and is currently associated with a session. Any object
|
||||
@@ -1058,7 +1076,7 @@ Glossary
|
||||
:ref:`session_object_states`
|
||||
|
||||
detached
|
||||
This describes one of the four major object states which
|
||||
This describes one of the major object states which
|
||||
an object can have within a :term:`session`; a detached object
|
||||
is an object that has a database identity (i.e. a primary key)
|
||||
but is not associated with any session. An object that
|
||||
|
||||
Vendored
+11
-3
@@ -14,8 +14,9 @@ A high level view and getting set up.
|
||||
:doc:`Overview <intro>` |
|
||||
:ref:`Installation Guide <installation>` |
|
||||
:doc:`Frequently Asked Questions <faq/index>` |
|
||||
:doc:`Migration from 0.9 <changelog/migration_10>` |
|
||||
:doc:`Migration from 1.2 <changelog/migration_13>` |
|
||||
:doc:`Glossary <glossary>` |
|
||||
:doc:`Error Messages <errors>` |
|
||||
:doc:`Changelog catalog <changelog/index>`
|
||||
|
||||
SQLAlchemy ORM
|
||||
@@ -38,7 +39,8 @@ of Python objects, proceed first to the tutorial.
|
||||
:doc:`Association Proxy <orm/extensions/associationproxy>` |
|
||||
:doc:`Hybrid Attributes <orm/extensions/hybrid>` |
|
||||
:doc:`Automap <orm/extensions/automap>` |
|
||||
:doc:`Mutable Scalars <orm/extensions/mutable>`
|
||||
:doc:`Mutable Scalars <orm/extensions/mutable>` |
|
||||
:doc:`Indexable <orm/extensions/indexable>`
|
||||
|
||||
* **ORM Usage:**
|
||||
:doc:`Session Usage and Guidelines <orm/session>` |
|
||||
@@ -96,5 +98,11 @@ Dialect Documentation
|
||||
The **dialect** is the system SQLAlchemy uses to communicate with various types of DBAPIs and databases.
|
||||
This section describes notes, options, and usage patterns regarding individual dialects.
|
||||
|
||||
:doc:`Index of all Dialects <dialects/index>`
|
||||
:doc:`PostgreSQL <dialects/postgresql>` |
|
||||
:doc:`MySQL <dialects/mysql>` |
|
||||
:doc:`SQLite <dialects/sqlite>` |
|
||||
:doc:`Oracle <dialects/oracle>` |
|
||||
:doc:`Microsoft SQL Server <dialects/mssql>`
|
||||
|
||||
:doc:`More Dialects ... <dialects/index>`
|
||||
|
||||
|
||||
Vendored
+31
-58
@@ -9,7 +9,7 @@ The SQLAlchemy SQL Toolkit and Object Relational Mapper
|
||||
is a comprehensive set of tools for working with
|
||||
databases and Python. It has several distinct areas of
|
||||
functionality which can be used individually or combined
|
||||
together. Its major components are illustrated in below,
|
||||
together. Its major components are illustrated below,
|
||||
with component dependencies organized into layers:
|
||||
|
||||
.. image:: sqla_arch_small.png
|
||||
@@ -70,45 +70,44 @@ Supported Platforms
|
||||
|
||||
SQLAlchemy has been tested against the following platforms:
|
||||
|
||||
* cPython since version 2.6, through the 2.xx series
|
||||
* cPython version 3, throughout all 3.xx series
|
||||
* `Pypy <http://pypy.org/>`_ 2.1 or greater
|
||||
* cPython 2.7
|
||||
* cPython 3.4 and higher
|
||||
* `PyPy <http://pypy.org/>`_ 2.1 or greater
|
||||
|
||||
.. versionchanged:: 0.9
|
||||
Python 2.6 is now the minimum Python version supported.
|
||||
.. versionchanged:: 1.2
|
||||
Python 2.7 is now the minimum Python version supported.
|
||||
|
||||
Platforms that don't currently have support include Jython, IronPython.
|
||||
.. versionchanged:: 1.3
|
||||
Within the Python 3 series, 3.4 is now the minimum Python 3 version supported.
|
||||
|
||||
Platforms that don't currently have support include Jython and IronPython.
|
||||
Jython has been supported in the past and may be supported in future
|
||||
releases as well, depending on the state of Jython itself.
|
||||
|
||||
Supported Installation Methods
|
||||
-------------------------------
|
||||
|
||||
SQLAlchemy supports installation using standard Python "distutils" or
|
||||
"setuptools" methodologies. An overview of potential setups is as follows:
|
||||
SQLAlchemy installation is via standard Python methodologies that are
|
||||
based on `setuptools <http://pypi.python.org/pypi/setuptools/>`_, either
|
||||
by referring to ``setup.py`` directly or by using
|
||||
`pip <http://pypi.python.org/pypi/pip/>`_ or other setuptools-compatible
|
||||
approaches.
|
||||
|
||||
* **Plain Python Distutils** - SQLAlchemy can be installed with a clean
|
||||
Python install using the services provided via `Python Distutils <http://docs.python.org/distutils/>`_,
|
||||
using the ``setup.py`` script. The C extensions as well as Python 3 builds are supported.
|
||||
* **Setuptools or Distribute** - When using `setuptools <http://pypi.python.org/pypi/setuptools/>`_,
|
||||
SQLAlchemy can be installed via ``setup.py`` or ``easy_install``, and the C
|
||||
extensions are supported.
|
||||
* **pip** - `pip <http://pypi.python.org/pypi/pip/>`_ is an installer that
|
||||
rides on top of ``setuptools`` or ``distribute``, replacing the usage
|
||||
of ``easy_install``. It is often preferred for its simpler mode of usage.
|
||||
.. versionchanged:: 1.1 setuptools is now required by the setup.py file;
|
||||
plain distutils installs are no longer supported.
|
||||
|
||||
Install via pip
|
||||
---------------
|
||||
|
||||
When ``pip`` is available, the distribution can be
|
||||
downloaded from Pypi and installed in one step::
|
||||
downloaded from PyPI and installed in one step::
|
||||
|
||||
pip install SQLAlchemy
|
||||
|
||||
This command will download the latest **released** version of SQLAlchemy from the `Python
|
||||
Cheese Shop <http://pypi.python.org/pypi/SQLAlchemy>`_ and install it to your system.
|
||||
|
||||
In order to install the latest **prerelease** version, such as ``1.0.0b1``,
|
||||
In order to install the latest **prerelease** version, such as ``1.3.0b1``,
|
||||
pip requires that the ``--pre`` flag be used::
|
||||
|
||||
pip install --pre SQLAlchemy
|
||||
@@ -124,6 +123,8 @@ Otherwise, you can install from the distribution using the ``setup.py`` script::
|
||||
|
||||
python setup.py install
|
||||
|
||||
.. _c_extensions:
|
||||
|
||||
Installing the C Extensions
|
||||
----------------------------------
|
||||
|
||||
@@ -131,14 +132,10 @@ SQLAlchemy includes C extensions which provide an extra speed boost for
|
||||
dealing with result sets. The extensions are supported on both the 2.xx
|
||||
and 3.xx series of cPython.
|
||||
|
||||
.. versionchanged:: 0.9.0
|
||||
|
||||
The C extensions now compile on Python 3 as well as Python 2.
|
||||
|
||||
``setup.py`` will automatically build the extensions if an appropriate platform is
|
||||
detected. If the build of the C extensions fails, due to missing compiler or
|
||||
other issue, the setup process will output a warning message, and re-run the
|
||||
build without the C extensions, upon completion reporting final status.
|
||||
detected. If the build of the C extensions fails due to a missing compiler or
|
||||
other issue, the setup process will output a warning message and re-run the
|
||||
build without the C extensions upon completion, reporting final status.
|
||||
|
||||
To run the build/install without even attempting to compile the C extensions,
|
||||
the ``DISABLE_SQLALCHEMY_CEXT`` environment variable may be specified. The
|
||||
@@ -146,36 +143,12 @@ use case for this is either for special testing circumstances, or in the rare
|
||||
case of compatibility/build issues not overcome by the usual "rebuild"
|
||||
mechanism::
|
||||
|
||||
# *** only in SQLAlchemy 0.9.4 / 0.8.6 or greater ***
|
||||
export DISABLE_SQLALCHEMY_CEXT=1; python setup.py install
|
||||
|
||||
.. versionadded:: 0.9.4,0.8.6 Support for disabling the build of
|
||||
C extensions using the ``DISABLE_SQLALCHEMY_CEXT`` environment variable
|
||||
has been added. This allows control of C extension building whether or not
|
||||
setuptools is available, and additionally works around the fact that
|
||||
setuptools will possibly be **removing support** for command-line switches
|
||||
such as ``--without-extensions`` in a future release.
|
||||
.. versionchanged:: 1.1 The legacy ``--without-cextensions`` flag has been
|
||||
removed from the installer as it relies on deprecated features of
|
||||
setuptools.
|
||||
|
||||
For versions of SQLAlchemy prior to 0.9.4 or 0.8.6, the
|
||||
``--without-cextensions`` option may be used to disable the attempt to build
|
||||
C extensions, provided setupools is in use, and provided the ``Feature``
|
||||
construct is supported by the installed version of setuptools::
|
||||
|
||||
python setup.py --without-cextensions install
|
||||
|
||||
Or with pip::
|
||||
|
||||
pip install --global-option='--without-cextensions' SQLAlchemy
|
||||
|
||||
|
||||
Installing on Python 3
|
||||
----------------------------------
|
||||
|
||||
SQLAlchemy runs directly on Python 2 or Python 3, and can be installed in
|
||||
either environment without any adjustments or code conversion.
|
||||
|
||||
.. versionchanged:: 0.9.0 Python 3 is now supported in place with no 2to3 step
|
||||
required.
|
||||
|
||||
|
||||
Installing a Database API
|
||||
@@ -189,7 +162,7 @@ the available DBAPIs for each database, including external links.
|
||||
Checking the Installed SQLAlchemy Version
|
||||
------------------------------------------
|
||||
|
||||
This documentation covers SQLAlchemy version 1.0. If you're working on a
|
||||
This documentation covers SQLAlchemy version 1.3. If you're working on a
|
||||
system that already has SQLAlchemy installed, check the version from your
|
||||
Python prompt like this:
|
||||
|
||||
@@ -197,11 +170,11 @@ Python prompt like this:
|
||||
|
||||
>>> import sqlalchemy
|
||||
>>> sqlalchemy.__version__ # doctest: +SKIP
|
||||
1.0.0
|
||||
1.3.0
|
||||
|
||||
.. _migration:
|
||||
|
||||
0.9 to 1.0 Migration
|
||||
1.2 to 1.3 Migration
|
||||
=====================
|
||||
|
||||
Notes on what's changed from 0.9 to 1.0 is available here at :doc:`changelog/migration_10`.
|
||||
Notes on what's changed from 1.2 to 1.3 is available here at :doc:`changelog/migration_13`.
|
||||
|
||||
Vendored
+5
-5
@@ -71,7 +71,7 @@ is ``None``::
|
||||
>>> a1 = Address()
|
||||
>>> u1.addresses
|
||||
[]
|
||||
>>> print a1.user
|
||||
>>> print(a1.user)
|
||||
None
|
||||
|
||||
However, once the ``Address`` is appended to the ``u1.addresses`` collection,
|
||||
@@ -105,7 +105,7 @@ exactly the same as if the above two relationships were created individually
|
||||
using :paramref:`~.relationship.back_populates` on each.
|
||||
|
||||
Backref Arguments
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
We've established that the :paramref:`~.relationship.backref` keyword is merely a shortcut for building
|
||||
two individual :func:`.relationship` constructs that refer to each other. Part of
|
||||
@@ -144,10 +144,10 @@ as if we limited the list of ``Address`` objects to those which start with "tony
|
||||
We can observe, by inspecting the resulting property, that both sides
|
||||
of the relationship have this join condition applied::
|
||||
|
||||
>>> print User.addresses.property.primaryjoin
|
||||
>>> print(User.addresses.property.primaryjoin)
|
||||
"user".id = address.user_id AND address.email LIKE :email_1 || '%%'
|
||||
>>>
|
||||
>>> print Address.user.property.primaryjoin
|
||||
>>> print(Address.user.property.primaryjoin)
|
||||
"user".id = address.user_id AND address.email LIKE :email_1 || '%%'
|
||||
>>>
|
||||
|
||||
@@ -187,7 +187,7 @@ it into a form that is interpreted by the receiving :func:`.relationship` as add
|
||||
arguments to be applied to the new relationship it creates.
|
||||
|
||||
One Way Backrefs
|
||||
~~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
An unusual case is that of the "one way backref". This is where the
|
||||
"back-populating" behavior of the backref is only desirable in one
|
||||
|
||||
+148
-38
@@ -1,21 +1,21 @@
|
||||
.. _relationship_patterns:
|
||||
|
||||
Basic Relationship Patterns
|
||||
----------------------------
|
||||
---------------------------
|
||||
|
||||
A quick walkthrough of the basic relational patterns.
|
||||
|
||||
The imports used for each of the following sections is as follows::
|
||||
|
||||
from sqlalchemy import Table, Column, Integer, ForeignKey
|
||||
from sqlalchemy.orm import relationship, backref
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
|
||||
Base = declarative_base()
|
||||
|
||||
|
||||
One To Many
|
||||
~~~~~~~~~~~~
|
||||
~~~~~~~~~~~
|
||||
|
||||
A one to many relationship places a foreign key on the child table referencing
|
||||
the parent. :func:`.relationship` is then specified on the parent, as referencing
|
||||
@@ -32,22 +32,34 @@ a collection of items represented by the child::
|
||||
parent_id = Column(Integer, ForeignKey('parent.id'))
|
||||
|
||||
To establish a bidirectional relationship in one-to-many, where the "reverse"
|
||||
side is a many to one, specify the :paramref:`~.relationship.backref` option::
|
||||
side is a many to one, specify an additional :func:`.relationship` and connect
|
||||
the two using the :paramref:`.relationship.back_populates` parameter::
|
||||
|
||||
class Parent(Base):
|
||||
__tablename__ = 'parent'
|
||||
id = Column(Integer, primary_key=True)
|
||||
children = relationship("Child", back_populates="parent")
|
||||
|
||||
class Child(Base):
|
||||
__tablename__ = 'child'
|
||||
id = Column(Integer, primary_key=True)
|
||||
parent_id = Column(Integer, ForeignKey('parent.id'))
|
||||
parent = relationship("Parent", back_populates="children")
|
||||
|
||||
``Child`` will get a ``parent`` attribute with many-to-one semantics.
|
||||
|
||||
Alternatively, the :paramref:`~.relationship.backref` option may be used
|
||||
on a single :func:`.relationship` instead of using
|
||||
:paramref:`~.relationship.back_populates`::
|
||||
|
||||
class Parent(Base):
|
||||
__tablename__ = 'parent'
|
||||
id = Column(Integer, primary_key=True)
|
||||
children = relationship("Child", backref="parent")
|
||||
|
||||
class Child(Base):
|
||||
__tablename__ = 'child'
|
||||
id = Column(Integer, primary_key=True)
|
||||
parent_id = Column(Integer, ForeignKey('parent.id'))
|
||||
|
||||
``Child`` will get a ``parent`` attribute with many-to-one semantics.
|
||||
|
||||
Many To One
|
||||
~~~~~~~~~~~~
|
||||
~~~~~~~~~~~
|
||||
|
||||
Many to one places a foreign key in the parent table referencing the child.
|
||||
:func:`.relationship` is declared on the parent, where a new scalar-holding
|
||||
@@ -63,9 +75,23 @@ attribute will be created::
|
||||
__tablename__ = 'child'
|
||||
id = Column(Integer, primary_key=True)
|
||||
|
||||
Bidirectional behavior is achieved by setting
|
||||
:paramref:`~.relationship.backref` to the value ``"parents"``, which
|
||||
will place a one-to-many collection on the ``Child`` class::
|
||||
Bidirectional behavior is achieved by adding a second :func:`.relationship`
|
||||
and applying the :paramref:`.relationship.back_populates` parameter
|
||||
in both directions::
|
||||
|
||||
class Parent(Base):
|
||||
__tablename__ = 'parent'
|
||||
id = Column(Integer, primary_key=True)
|
||||
child_id = Column(Integer, ForeignKey('child.id'))
|
||||
child = relationship("Child", back_populates="parents")
|
||||
|
||||
class Child(Base):
|
||||
__tablename__ = 'child'
|
||||
id = Column(Integer, primary_key=True)
|
||||
parents = relationship("Parent", back_populates="child")
|
||||
|
||||
Alternatively, the :paramref:`~.relationship.backref` parameter
|
||||
may be applied to a single :func:`.relationship`, such as ``Parent.child``::
|
||||
|
||||
class Parent(Base):
|
||||
__tablename__ = 'parent'
|
||||
@@ -76,7 +102,7 @@ will place a one-to-many collection on the ``Child`` class::
|
||||
.. _relationships_one_to_one:
|
||||
|
||||
One To One
|
||||
~~~~~~~~~~~
|
||||
~~~~~~~~~~
|
||||
|
||||
One To One is essentially a bidirectional relationship with a scalar
|
||||
attribute on both sides. To achieve this, the :paramref:`~.relationship.uselist` flag indicates
|
||||
@@ -86,15 +112,32 @@ of the relationship. To convert one-to-many into one-to-one::
|
||||
class Parent(Base):
|
||||
__tablename__ = 'parent'
|
||||
id = Column(Integer, primary_key=True)
|
||||
child = relationship("Child", uselist=False, backref="parent")
|
||||
child = relationship("Child", uselist=False, back_populates="parent")
|
||||
|
||||
class Child(Base):
|
||||
__tablename__ = 'child'
|
||||
id = Column(Integer, primary_key=True)
|
||||
parent_id = Column(Integer, ForeignKey('parent.id'))
|
||||
parent = relationship("Parent", back_populates="child")
|
||||
|
||||
Or to turn a one-to-many backref into one-to-one, use the :func:`.backref` function
|
||||
to provide arguments for the reverse side::
|
||||
Or for many-to-one::
|
||||
|
||||
class Parent(Base):
|
||||
__tablename__ = 'parent'
|
||||
id = Column(Integer, primary_key=True)
|
||||
child_id = Column(Integer, ForeignKey('child.id'))
|
||||
child = relationship("Child", back_populates="parent")
|
||||
|
||||
class Child(Base):
|
||||
__tablename__ = 'child'
|
||||
id = Column(Integer, primary_key=True)
|
||||
parent = relationship("Parent", back_populates="child", uselist=False)
|
||||
|
||||
As always, the :paramref:`.relationship.backref` and :func:`.backref` functions
|
||||
may be used in lieu of the :paramref:`.relationship.back_populates` approach;
|
||||
to specify ``uselist`` on a backref, use the :func:`.backref` function::
|
||||
|
||||
from sqlalchemy.orm import backref
|
||||
|
||||
class Parent(Base):
|
||||
__tablename__ = 'parent'
|
||||
@@ -102,14 +145,11 @@ to provide arguments for the reverse side::
|
||||
child_id = Column(Integer, ForeignKey('child.id'))
|
||||
child = relationship("Child", backref=backref("parent", uselist=False))
|
||||
|
||||
class Child(Base):
|
||||
__tablename__ = 'child'
|
||||
id = Column(Integer, primary_key=True)
|
||||
|
||||
.. _relationships_many_to_many:
|
||||
|
||||
Many To Many
|
||||
~~~~~~~~~~~~~
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Many to Many adds an association table between two classes. The association
|
||||
table is indicated by the :paramref:`~.relationship.secondary` argument to
|
||||
@@ -133,7 +173,32 @@ directives can locate the remote tables with which to link::
|
||||
id = Column(Integer, primary_key=True)
|
||||
|
||||
For a bidirectional relationship, both sides of the relationship contain a
|
||||
collection. The :paramref:`~.relationship.backref` keyword will automatically use
|
||||
collection. Specify using :paramref:`.relationship.back_populates`, and
|
||||
for each :func:`.relationship` specify the common association table::
|
||||
|
||||
association_table = Table('association', Base.metadata,
|
||||
Column('left_id', Integer, ForeignKey('left.id')),
|
||||
Column('right_id', Integer, ForeignKey('right.id'))
|
||||
)
|
||||
|
||||
class Parent(Base):
|
||||
__tablename__ = 'left'
|
||||
id = Column(Integer, primary_key=True)
|
||||
children = relationship(
|
||||
"Child",
|
||||
secondary=association_table,
|
||||
back_populates="parents")
|
||||
|
||||
class Child(Base):
|
||||
__tablename__ = 'right'
|
||||
id = Column(Integer, primary_key=True)
|
||||
parents = relationship(
|
||||
"Parent",
|
||||
secondary=association_table,
|
||||
back_populates="children")
|
||||
|
||||
When using the :paramref:`~.relationship.backref` parameter instead of
|
||||
:paramref:`.relationship.back_populates`, the backref will automatically use
|
||||
the same :paramref:`~.relationship.secondary` argument for the reverse relationship::
|
||||
|
||||
association_table = Table('association', Base.metadata,
|
||||
@@ -206,7 +271,7 @@ There are several possibilities here:
|
||||
suppose it's called ``Child.parents``, SQLAlchemy by default will load in
|
||||
the ``Child.parents`` collection to locate all ``Parent`` objects, and remove
|
||||
each row from the "secondary" table which establishes this link. Note that
|
||||
this relationship does not need to be bidrectional; SQLAlchemy is strictly
|
||||
this relationship does not need to be bidirectional; SQLAlchemy is strictly
|
||||
looking at every :func:`.relationship` associated with the ``Child`` object
|
||||
being deleted.
|
||||
* A higher performing option here is to use ON DELETE CASCADE directives
|
||||
@@ -259,23 +324,26 @@ is stored along with each association between ``Parent`` and
|
||||
__tablename__ = 'right'
|
||||
id = Column(Integer, primary_key=True)
|
||||
|
||||
The bidirectional version adds backrefs to both relationships::
|
||||
As always, the bidirectional version makes use of :paramref:`.relationship.back_populates`
|
||||
or :paramref:`.relationship.backref`::
|
||||
|
||||
class Association(Base):
|
||||
__tablename__ = 'association'
|
||||
left_id = Column(Integer, ForeignKey('left.id'), primary_key=True)
|
||||
right_id = Column(Integer, ForeignKey('right.id'), primary_key=True)
|
||||
extra_data = Column(String(50))
|
||||
child = relationship("Child", backref="parent_assocs")
|
||||
child = relationship("Child", back_populates="parents")
|
||||
parent = relationship("Parent", back_populates="children")
|
||||
|
||||
class Parent(Base):
|
||||
__tablename__ = 'left'
|
||||
id = Column(Integer, primary_key=True)
|
||||
children = relationship("Association", backref="parent")
|
||||
children = relationship("Association", back_populates="parent")
|
||||
|
||||
class Child(Base):
|
||||
__tablename__ = 'right'
|
||||
id = Column(Integer, primary_key=True)
|
||||
parents = relationship("Association", back_populates="child")
|
||||
|
||||
Working with the association pattern in its direct form requires that child
|
||||
objects are associated with an association instance before being appended to
|
||||
@@ -291,8 +359,8 @@ association object::
|
||||
# iterate through child objects via association, including association
|
||||
# attributes
|
||||
for assoc in p.children:
|
||||
print assoc.extra_data
|
||||
print assoc.child
|
||||
print(assoc.extra_data)
|
||||
print(assoc.child)
|
||||
|
||||
To enhance the association object pattern such that direct
|
||||
access to the ``Association`` object is optional, SQLAlchemy
|
||||
@@ -301,13 +369,55 @@ extension allows the configuration of attributes which will
|
||||
access two "hops" with a single access, one "hop" to the
|
||||
associated object, and a second to a target attribute.
|
||||
|
||||
.. note::
|
||||
.. warning::
|
||||
|
||||
When using the association object pattern, it is advisable that the
|
||||
association-mapped table not be used as the
|
||||
:paramref:`~.relationship.secondary` argument on a
|
||||
:func:`.relationship` elsewhere, unless that :func:`.relationship`
|
||||
contains the option :paramref:`~.relationship.viewonly` set to
|
||||
``True``. SQLAlchemy otherwise may attempt to emit redundant INSERT
|
||||
and DELETE statements on the same table, if similar state is
|
||||
detected on the related attribute as well as the associated object.
|
||||
The association object pattern **does not coordinate changes with a
|
||||
separate relationship that maps the association table as "secondary"**.
|
||||
|
||||
Below, changes made to ``Parent.children`` will not be coordinated
|
||||
with changes made to ``Parent.child_associations`` or
|
||||
``Child.parent_associations`` in Python; while all of these relationships will continue
|
||||
to function normally by themselves, changes on one will not show up in another
|
||||
until the :class:`.Session` is expired, which normally occurs automatically
|
||||
after :meth:`.Session.commit`::
|
||||
|
||||
class Association(Base):
|
||||
__tablename__ = 'association'
|
||||
|
||||
left_id = Column(Integer, ForeignKey('left.id'), primary_key=True)
|
||||
right_id = Column(Integer, ForeignKey('right.id'), primary_key=True)
|
||||
extra_data = Column(String(50))
|
||||
|
||||
child = relationship("Child", backref="parent_associations")
|
||||
parent = relationship("Parent", backref="child_associations")
|
||||
|
||||
class Parent(Base):
|
||||
__tablename__ = 'left'
|
||||
id = Column(Integer, primary_key=True)
|
||||
|
||||
children = relationship("Child", secondary="association")
|
||||
|
||||
class Child(Base):
|
||||
__tablename__ = 'right'
|
||||
id = Column(Integer, primary_key=True)
|
||||
|
||||
Additionally, just as changes to one relationship aren't reflected in the
|
||||
others automatically, writing the same data to both relationships will cause
|
||||
conflicting INSERT or DELETE statements as well, such as below where we
|
||||
establish the same relationship between a ``Parent`` and ``Child`` object
|
||||
twice::
|
||||
|
||||
p1 = Parent()
|
||||
c1 = Child()
|
||||
p1.children.append(c1)
|
||||
|
||||
# redundant, will cause a duplicate INSERT on Association
|
||||
p1.parent_associations.append(Association(child=c1))
|
||||
|
||||
It's fine to use a mapping like the above if you know what
|
||||
you're doing, though it may be a good idea to apply the ``viewonly=True`` parameter
|
||||
to the "secondary" relationship to avoid the issue of redundant changes
|
||||
being logged. However, to get a foolproof pattern that allows a simple
|
||||
two-object ``Parent->Child`` relationship while still using the association
|
||||
object pattern, use the association proxy extension
|
||||
as documented at :ref:`associationproxy_toplevel`.
|
||||
|
||||
Vendored
+3
-3
@@ -17,7 +17,7 @@ the :ref:`cascade_delete` and :ref:`cascade_delete_orphan` options;
|
||||
these settings are appropriate for related objects which only exist as
|
||||
long as they are attached to their parent, and are otherwise deleted.
|
||||
|
||||
Cascade behavior is configured using the by changing the
|
||||
Cascade behavior is configured using the
|
||||
:paramref:`~.relationship.cascade` option on
|
||||
:func:`~sqlalchemy.orm.relationship`::
|
||||
|
||||
@@ -131,7 +131,7 @@ delete
|
||||
|
||||
The ``delete`` cascade indicates that when a "parent" object
|
||||
is marked for deletion, its related "child" objects should also be marked
|
||||
for deletion. If for example we we have a relationship ``User.addresses``
|
||||
for deletion. If for example we have a relationship ``User.addresses``
|
||||
with ``delete`` cascade configured::
|
||||
|
||||
class User(Base):
|
||||
@@ -341,7 +341,7 @@ easily described through demonstration; it means that, given a mapping such as t
|
||||
})
|
||||
|
||||
If an ``Order`` is already in the session, and is assigned to the ``order``
|
||||
attribute of an ``Item``, the backref appends the ``Order`` to the ``items``
|
||||
attribute of an ``Item``, the backref appends the ``Item`` to the ``items``
|
||||
collection of that ``Order``, resulting in the ``save-update`` cascade taking
|
||||
place::
|
||||
|
||||
|
||||
Vendored
+46
-12
@@ -16,7 +16,7 @@ and techniques.
|
||||
.. currentmodule:: sqlalchemy.orm
|
||||
|
||||
Working with Large Collections
|
||||
===============================
|
||||
==============================
|
||||
|
||||
The default behavior of :func:`.relationship` is to fully load
|
||||
the collection of items in, as according to the loading strategy of the
|
||||
@@ -31,7 +31,7 @@ loading of child items both at load time as well as deletion time.
|
||||
.. _dynamic_relationship:
|
||||
|
||||
Dynamic Relationship Loaders
|
||||
-----------------------------
|
||||
----------------------------
|
||||
|
||||
A key feature to enable management of a large collection is the so-called "dynamic"
|
||||
relationship. This is an optional form of :func:`~sqlalchemy.orm.relationship` which
|
||||
@@ -91,8 +91,10 @@ Note that eager/lazy loading options cannot be used in conjunction dynamic relat
|
||||
relationships. Newer versions of SQLAlchemy emit warnings or exceptions
|
||||
in these cases.
|
||||
|
||||
Setting Noload
|
||||
---------------
|
||||
.. _collections_noload_raiseload:
|
||||
|
||||
Setting Noload, RaiseLoad
|
||||
-------------------------
|
||||
|
||||
A "noload" relationship never loads from the database, even when
|
||||
accessed. It is configured using ``lazy='noload'``::
|
||||
@@ -105,12 +107,40 @@ accessed. It is configured using ``lazy='noload'``::
|
||||
Above, the ``children`` collection is fully writeable, and changes to it will
|
||||
be persisted to the database as well as locally available for reading at the
|
||||
time they are added. However when instances of ``MyClass`` are freshly loaded
|
||||
from the database, the ``children`` collection stays empty.
|
||||
from the database, the ``children`` collection stays empty. The noload
|
||||
strategy is also available on a query option basis using the
|
||||
:func:`.orm.noload` loader option.
|
||||
|
||||
Alternatively, a "raise"-loaded relationship will raise an
|
||||
:exc:`~sqlalchemy.exc.InvalidRequestError` where the attribute would normally
|
||||
emit a lazy load::
|
||||
|
||||
class MyClass(Base):
|
||||
__tablename__ = 'some_table'
|
||||
|
||||
children = relationship(MyOtherClass, lazy='raise')
|
||||
|
||||
Above, attribute access on the ``children`` collection will raise an exception
|
||||
if it was not previously eagerloaded. This includes read access but for
|
||||
collections will also affect write access, as collections can't be mutated
|
||||
without first loading them. The rationale for this is to ensure that an
|
||||
application is not emitting any unexpected lazy loads within a certain context.
|
||||
Rather than having to read through SQL logs to determine that all necessary
|
||||
attributes were eager loaded, the "raise" strategy will cause unloaded
|
||||
attributes to raise immediately if accessed. The raise strategy is
|
||||
also available on a query option basis using the :func:`.orm.raiseload`
|
||||
loader option.
|
||||
|
||||
.. versionadded:: 1.1 added the "raise" loader strategy.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`prevent_lazy_with_raiseload`
|
||||
|
||||
.. _passive_deletes:
|
||||
|
||||
Using Passive Deletes
|
||||
----------------------
|
||||
---------------------
|
||||
|
||||
Use :paramref:`~.relationship.passive_deletes` to disable child object loading on a DELETE
|
||||
operation, in conjunction with "ON DELETE (CASCADE|SET NULL)" on your database
|
||||
@@ -150,6 +180,10 @@ instances of ``MyOtherClass`` which are not loaded, SQLAlchemy assumes that
|
||||
"ON DELETE CASCADE" rules will ensure that those rows are deleted by the
|
||||
database.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:paramref:`.orm.mapper.passive_deletes` - similar feature on :func:`.mapper`
|
||||
|
||||
.. currentmodule:: sqlalchemy.orm.collections
|
||||
.. _custom_collections:
|
||||
|
||||
@@ -168,7 +202,7 @@ this collection is a ``list``::
|
||||
|
||||
parent = Parent()
|
||||
parent.children.append(Child())
|
||||
print parent.children[0]
|
||||
print(parent.children[0])
|
||||
|
||||
Collections are not limited to lists. Sets, mutable sequences and almost any
|
||||
other Python object that can act as a container can be used in place of the
|
||||
@@ -188,7 +222,7 @@ default list, by specifying the :paramref:`~.relationship.collection_class` opti
|
||||
assert child in parent.children
|
||||
|
||||
Dictionary Collections
|
||||
-----------------------
|
||||
----------------------
|
||||
|
||||
A little extra detail is needed when using a dictionary as a collection.
|
||||
This because objects are always loaded from the database as lists, and a key-generation
|
||||
@@ -316,10 +350,10 @@ for examples.
|
||||
.. autofunction:: mapped_collection
|
||||
|
||||
Custom Collection Implementations
|
||||
==================================
|
||||
=================================
|
||||
|
||||
You can use your own types for collections as well. In simple cases,
|
||||
inherting from ``list`` or ``set``, adding custom behavior, is all that's needed.
|
||||
inheriting from ``list`` or ``set``, adding custom behavior, is all that's needed.
|
||||
In other cases, special decorators are needed to tell SQLAlchemy more detail
|
||||
about how the collection operates.
|
||||
|
||||
@@ -420,7 +454,7 @@ collections. Use them when your class doesn't quite meet the regular interface
|
||||
for its container type, or when you otherwise would like to use a different method to
|
||||
get the job done.
|
||||
|
||||
.. sourcecode:: python+sql
|
||||
.. sourcecode:: python
|
||||
|
||||
from sqlalchemy.orm.collections import collection
|
||||
|
||||
@@ -565,7 +599,7 @@ The ORM uses this approach for built-ins, quietly substituting a trivial
|
||||
subclass when a ``list``, ``set`` or ``dict`` is used directly.
|
||||
|
||||
Collection Internals
|
||||
=====================
|
||||
====================
|
||||
|
||||
Various internal methods.
|
||||
|
||||
|
||||
Vendored
+86
-31
@@ -3,22 +3,12 @@
|
||||
.. _mapper_composite:
|
||||
|
||||
Composite Column Types
|
||||
=======================
|
||||
======================
|
||||
|
||||
Sets of columns can be associated with a single user-defined datatype. The ORM
|
||||
provides a single attribute which represents the group of columns using the
|
||||
class you provide.
|
||||
|
||||
.. versionchanged:: 0.7
|
||||
Composites have been simplified such that
|
||||
they no longer "conceal" the underlying column based attributes. Additionally,
|
||||
in-place mutation is no longer automatic; see the section below on
|
||||
enabling mutability to support tracking of in-place changes.
|
||||
|
||||
.. versionchanged:: 0.9
|
||||
Composites will return their object-form, rather than as individual columns,
|
||||
when used in a column-oriented :class:`.Query` construct. See :ref:`migration_2824`.
|
||||
|
||||
A simple example represents pairs of columns as a ``Point`` object.
|
||||
``Point`` represents such a pair as ``.x`` and ``.y``::
|
||||
|
||||
@@ -48,7 +38,7 @@ the object as a list or tuple, in order of its column-based attributes. It
|
||||
also should supply adequate ``__eq__()`` and ``__ne__()`` methods which test
|
||||
the equality of two instances.
|
||||
|
||||
We will create a mapping to a table ``vertice``, which represents two points
|
||||
We will create a mapping to a table ``vertices``, which represents two points
|
||||
as ``x1/y1`` and ``x2/y2``. These are created normally as :class:`.Column`
|
||||
objects. Then, the :func:`.composite` function is used to assign new
|
||||
attributes that will represent sets of columns via the ``Point`` class::
|
||||
@@ -60,7 +50,7 @@ attributes that will represent sets of columns via the ``Point`` class::
|
||||
Base = declarative_base()
|
||||
|
||||
class Vertex(Base):
|
||||
__tablename__ = 'vertice'
|
||||
__tablename__ = 'vertices'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
x1 = Column(Integer)
|
||||
@@ -74,9 +64,9 @@ attributes that will represent sets of columns via the ``Point`` class::
|
||||
A classical mapping above would define each :func:`.composite`
|
||||
against the existing table::
|
||||
|
||||
mapper(Vertex, vertice_table, properties={
|
||||
'start':composite(Point, vertice_table.c.x1, vertice_table.c.y1),
|
||||
'end':composite(Point, vertice_table.c.x2, vertice_table.c.y2),
|
||||
mapper(Vertex, vertices_table, properties={
|
||||
'start':composite(Point, vertices_table.c.x1, vertices_table.c.y1),
|
||||
'end':composite(Point, vertices_table.c.x2, vertices_table.c.y2),
|
||||
})
|
||||
|
||||
We can now persist and use ``Vertex`` instances, as well as query for them,
|
||||
@@ -87,17 +77,17 @@ using the ``.start`` and ``.end`` attributes against ad-hoc ``Point`` instances:
|
||||
>>> v = Vertex(start=Point(3, 4), end=Point(5, 6))
|
||||
>>> session.add(v)
|
||||
>>> q = session.query(Vertex).filter(Vertex.start == Point(3, 4))
|
||||
{sql}>>> print q.first().start
|
||||
{sql}>>> print(q.first().start)
|
||||
BEGIN (implicit)
|
||||
INSERT INTO vertice (x1, y1, x2, y2) VALUES (?, ?, ?, ?)
|
||||
INSERT INTO vertices (x1, y1, x2, y2) VALUES (?, ?, ?, ?)
|
||||
(3, 4, 5, 6)
|
||||
SELECT vertice.id AS vertice_id,
|
||||
vertice.x1 AS vertice_x1,
|
||||
vertice.y1 AS vertice_y1,
|
||||
vertice.x2 AS vertice_x2,
|
||||
vertice.y2 AS vertice_y2
|
||||
FROM vertice
|
||||
WHERE vertice.x1 = ? AND vertice.y1 = ?
|
||||
SELECT vertices.id AS vertices_id,
|
||||
vertices.x1 AS vertices_x1,
|
||||
vertices.y1 AS vertices_y1,
|
||||
vertices.x2 AS vertices_x2,
|
||||
vertices.y2 AS vertices_y2
|
||||
FROM vertices
|
||||
WHERE vertices.x1 = ? AND vertices.y1 = ?
|
||||
LIMIT ? OFFSET ?
|
||||
(3, 4, 1, 0)
|
||||
{stop}Point(x=3, y=4)
|
||||
@@ -115,11 +105,6 @@ via the usage of the :class:`.MutableComposite` mixin, which uses events
|
||||
to associate each user-defined composite object with all parent associations.
|
||||
Please see the example in :ref:`mutable_composites`.
|
||||
|
||||
.. versionchanged:: 0.7
|
||||
In-place changes to an existing composite value are no longer
|
||||
tracked automatically; the functionality is superseded by the
|
||||
:class:`.MutableComposite` class.
|
||||
|
||||
.. _composite_operations:
|
||||
|
||||
Redefining Comparison Operations for Composites
|
||||
@@ -145,7 +130,7 @@ the same expression that the base "greater than" does::
|
||||
other.__composite_values__())])
|
||||
|
||||
class Vertex(Base):
|
||||
___tablename__ = 'vertice'
|
||||
___tablename__ = 'vertices'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
x1 = Column(Integer)
|
||||
@@ -158,3 +143,73 @@ the same expression that the base "greater than" does::
|
||||
end = composite(Point, x2, y2,
|
||||
comparator_factory=PointComparator)
|
||||
|
||||
Nesting Composites
|
||||
-------------------
|
||||
|
||||
Composite objects can be defined to work in simple nested schemes, by
|
||||
redefining behaviors within the composite class to work as desired, then
|
||||
mapping the composite class to the full length of individual columns normally.
|
||||
Typically, it is convenient to define separate constructors for user-defined
|
||||
use and generate-from-row use. Below we reorganize the ``Vertex`` class to
|
||||
itself be a composite object, which is then mapped to a class ``HasVertex``::
|
||||
|
||||
from sqlalchemy.orm import composite
|
||||
|
||||
class Point(object):
|
||||
def __init__(self, x, y):
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
def __composite_values__(self):
|
||||
return self.x, self.y
|
||||
|
||||
def __repr__(self):
|
||||
return "Point(x=%r, y=%r)" % (self.x, self.y)
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, Point) and \
|
||||
other.x == self.x and \
|
||||
other.y == self.y
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
class Vertex(object):
|
||||
def __init__(self, start, end):
|
||||
self.start = start
|
||||
self.end = end
|
||||
|
||||
@classmethod
|
||||
def _generate(self, x1, y1, x2, y2):
|
||||
"""generate a Vertex from a row"""
|
||||
return Vertex(
|
||||
Point(x1, y1),
|
||||
Point(x2, y2)
|
||||
)
|
||||
|
||||
def __composite_values__(self):
|
||||
return \
|
||||
self.start.__composite_values__() + \
|
||||
self.end.__composite_values__()
|
||||
|
||||
class HasVertex(Base):
|
||||
__tablename__ = 'has_vertex'
|
||||
id = Column(Integer, primary_key=True)
|
||||
x1 = Column(Integer)
|
||||
y1 = Column(Integer)
|
||||
x2 = Column(Integer)
|
||||
y2 = Column(Integer)
|
||||
|
||||
vertex = composite(Vertex._generate, x1, y1, x2, y2)
|
||||
|
||||
We can then use the above mapping as::
|
||||
|
||||
hv = HasVertex(vertex=Vertex(Point(1, 2), Point(3, 4)))
|
||||
|
||||
s.add(hv)
|
||||
s.commit()
|
||||
|
||||
hv = s.query(HasVertex).filter(
|
||||
HasVertex.vertex == Vertex(Point(1, 2), Point(3, 4))).first()
|
||||
print(hv.vertex.start)
|
||||
print(hv.vertex.end)
|
||||
|
||||
Vendored
+18
-14
@@ -3,7 +3,7 @@
|
||||
.. _mapping_constructors:
|
||||
|
||||
Constructors and Object Initialization
|
||||
=======================================
|
||||
======================================
|
||||
|
||||
Mapping imposes no restrictions or requirements on the constructor
|
||||
(``__init__``) method for the class. You are free to require any arguments for
|
||||
@@ -18,10 +18,13 @@ then quietly restoring attributes directly on the instance rather than calling
|
||||
``__init__``.
|
||||
|
||||
If you need to do some setup on database-loaded instances before they're ready
|
||||
to use, you can use the ``@reconstructor`` decorator to tag a method as the
|
||||
ORM counterpart to ``__init__``. SQLAlchemy will call this method with no
|
||||
arguments every time it loads or reconstructs one of your instances. This is
|
||||
useful for recreating transient properties that are normally assigned in your
|
||||
to use, there is an event hook known as :meth:`.InstanceEvents.load` which
|
||||
can achieve this; it is also available via a class-specific decorator called
|
||||
:func:`.orm.reconstructor`. When using :func:`.orm.reconstructor`,
|
||||
the mapper will invoke the decorated method with no
|
||||
arguments every time it loads or reconstructs an instance of the
|
||||
class. This is
|
||||
useful for recreating transient properties that are normally assigned in
|
||||
``__init__``::
|
||||
|
||||
from sqlalchemy import orm
|
||||
@@ -36,21 +39,22 @@ useful for recreating transient properties that are normally assigned in your
|
||||
def init_on_load(self):
|
||||
self.stuff = []
|
||||
|
||||
When ``obj = MyMappedClass()`` is executed, Python calls the ``__init__``
|
||||
method as normal and the ``data`` argument is required. When instances are
|
||||
Above, when ``obj = MyMappedClass()`` is executed, the ``__init__`` constructor
|
||||
is invoked normally and the ``data`` argument is required. When instances are
|
||||
loaded during a :class:`~sqlalchemy.orm.query.Query` operation as in
|
||||
``query(MyMappedClass).one()``, ``init_on_load`` is called.
|
||||
|
||||
Any method may be tagged as the :func:`~sqlalchemy.orm.reconstructor`, even
|
||||
the ``__init__`` method. SQLAlchemy will call the reconstructor method with no
|
||||
arguments. Scalar (non-collection) database-mapped attributes of the instance
|
||||
will be available for use within the function. Eagerly-loaded collections are
|
||||
generally not yet available and will usually only contain the first element.
|
||||
Any method may be tagged as the :func:`.orm.reconstructor`, even
|
||||
the ``__init__`` method itself. It is invoked after all immediate
|
||||
column-level attributes are loaded as well as after eagerly-loaded scalar
|
||||
relationships. Eagerly loaded collections may be only partially populated
|
||||
or not populated at all, depending on the kind of eager loading used.
|
||||
|
||||
ORM state changes made to objects at this stage will not be recorded for the
|
||||
next flush() operation, so the activity within a reconstructor should be
|
||||
next flush operation, so the activity within a reconstructor should be
|
||||
conservative.
|
||||
|
||||
:func:`~sqlalchemy.orm.reconstructor` is a shortcut into a larger system
|
||||
:func:`.orm.reconstructor` is a shortcut into a larger system
|
||||
of "instance level" events, which can be subscribed to using the
|
||||
event API - see :class:`.InstanceEvents` for the full API description
|
||||
of these events.
|
||||
|
||||
Vendored
+4
-4
@@ -1,7 +1,7 @@
|
||||
.. _unitofwork_contextual:
|
||||
|
||||
Contextual/Thread-local Sessions
|
||||
=================================
|
||||
================================
|
||||
|
||||
Recall from the section :ref:`session_faq_whentocreate`, the concept of
|
||||
"session scopes" was introduced, with an emphasis on web applications
|
||||
@@ -96,9 +96,9 @@ underlying :class:`.Session` being maintained by the registry::
|
||||
# equivalent to:
|
||||
#
|
||||
# session = Session()
|
||||
# print session.query(MyClass).all()
|
||||
# print(session.query(MyClass).all())
|
||||
#
|
||||
print Session.query(MyClass).all()
|
||||
print(Session.query(MyClass).all())
|
||||
|
||||
The above code accomplishes the same task as that of acquiring the current
|
||||
:class:`.Session` by calling upon the registry, then using that :class:`.Session`.
|
||||
@@ -113,7 +113,7 @@ object is entirely designed to be used in a **non-concurrent** fashion, which
|
||||
in terms of multithreading means "only in one thread at a time". So our
|
||||
above example of :class:`.scoped_session` usage, where the same :class:`.Session`
|
||||
object is maintained across multiple calls, suggests that some process needs
|
||||
to be in place such that mutltiple calls across many threads don't actually get
|
||||
to be in place such that multiple calls across many threads don't actually get
|
||||
a handle to the same session. We call this notion **thread local storage**,
|
||||
which means, a special object is used that will maintain a distinct object
|
||||
per each application thread. Python provides this via the
|
||||
|
||||
Vendored
+4
-4
@@ -3,7 +3,7 @@
|
||||
.. _dep_interfaces_orm_toplevel:
|
||||
|
||||
Deprecated ORM Event Interfaces
|
||||
================================
|
||||
===============================
|
||||
|
||||
.. module:: sqlalchemy.orm.interfaces
|
||||
|
||||
@@ -17,19 +17,19 @@ until SQLAlchemy 0.5. The non-ORM analogue is described at :ref:`dep_interfaces
|
||||
a consistent interface to all events without the need for subclassing.
|
||||
|
||||
Mapper Events
|
||||
-----------------
|
||||
-------------
|
||||
|
||||
.. autoclass:: MapperExtension
|
||||
:members:
|
||||
|
||||
Session Events
|
||||
-----------------
|
||||
--------------
|
||||
|
||||
.. autoclass:: SessionExtension
|
||||
:members:
|
||||
|
||||
Attribute Events
|
||||
--------------------
|
||||
----------------
|
||||
|
||||
.. autoclass:: AttributeExtension
|
||||
:members:
|
||||
|
||||
Vendored
+7
-9
@@ -5,12 +5,10 @@ ORM Events
|
||||
|
||||
The ORM includes a wide variety of hooks available for subscription.
|
||||
|
||||
.. versionadded:: 0.7
|
||||
The event supersedes the previous system of "extension" classes.
|
||||
|
||||
For an introduction to the event API, see :ref:`event_toplevel`. Non-ORM events
|
||||
such as those regarding connections and low-level statement execution are described in
|
||||
:ref:`core_event_toplevel`.
|
||||
For an introduction to the most commonly used ORM events, see the section
|
||||
:ref:`session_events_toplevel`. The event system in general is discussed
|
||||
at :ref:`event_toplevel`. Non-ORM events such as those regarding connections
|
||||
and low-level statement execution are described in :ref:`core_event_toplevel`.
|
||||
|
||||
Attribute Events
|
||||
----------------
|
||||
@@ -19,7 +17,7 @@ Attribute Events
|
||||
:members:
|
||||
|
||||
Mapper Events
|
||||
---------------
|
||||
-------------
|
||||
|
||||
.. autoclass:: sqlalchemy.orm.events.MapperEvents
|
||||
:members:
|
||||
@@ -37,13 +35,13 @@ Session Events
|
||||
:members:
|
||||
|
||||
Query Events
|
||||
-------------
|
||||
------------
|
||||
|
||||
.. autoclass:: sqlalchemy.orm.events.QueryEvents
|
||||
:members:
|
||||
|
||||
Instrumentation Events
|
||||
-----------------------
|
||||
----------------------
|
||||
|
||||
.. automodule:: sqlalchemy.orm.instrumentation
|
||||
|
||||
|
||||
Vendored
+26
-13
@@ -36,19 +36,19 @@ Directed Graphs
|
||||
.. automodule:: examples.graphs
|
||||
|
||||
Dynamic Relations as Dictionaries
|
||||
------------------------------------
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: examples.dynamic_dict
|
||||
|
||||
.. _examples_generic_associations:
|
||||
|
||||
Generic Associations
|
||||
------------------------
|
||||
--------------------
|
||||
|
||||
.. automodule:: examples.generic_associations
|
||||
|
||||
Large Collections
|
||||
------------------------
|
||||
-----------------
|
||||
|
||||
.. automodule:: examples.large_collection
|
||||
|
||||
@@ -58,7 +58,7 @@ Materialized Paths
|
||||
.. automodule:: examples.materialized_paths
|
||||
|
||||
Nested Sets
|
||||
------------
|
||||
-----------
|
||||
|
||||
.. automodule:: examples.nested_sets
|
||||
|
||||
@@ -76,15 +76,22 @@ Relationship Join Conditions
|
||||
|
||||
.. automodule:: examples.join_conditions
|
||||
|
||||
.. _examples_spaceinvaders:
|
||||
|
||||
Space Invaders
|
||||
--------------
|
||||
|
||||
.. automodule:: examples.space_invaders
|
||||
|
||||
.. _examples_xmlpersistence:
|
||||
|
||||
XML Persistence
|
||||
------------------------
|
||||
---------------
|
||||
|
||||
.. automodule:: examples.elementtree
|
||||
|
||||
Versioning Objects
|
||||
------------------------
|
||||
------------------
|
||||
|
||||
.. _examples_versioned_history:
|
||||
|
||||
@@ -93,22 +100,28 @@ Versioning with a History Table
|
||||
|
||||
.. automodule:: examples.versioned_history
|
||||
|
||||
.. _examples_versioned_rows:
|
||||
|
||||
Versioning using Temporal Rows
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. automodule:: examples.versioned_rows
|
||||
|
||||
.. _examples_vertical_tables:
|
||||
|
||||
Vertical Attribute Mapping
|
||||
------------------------------------
|
||||
--------------------------
|
||||
|
||||
.. automodule:: examples.vertical
|
||||
|
||||
|
||||
.. _examples_inheritance:
|
||||
|
||||
Inheritance Mapping Recipes
|
||||
============================
|
||||
===========================
|
||||
|
||||
Basic Inheritance Mappings
|
||||
----------------------------------
|
||||
--------------------------
|
||||
|
||||
.. automodule:: examples.inheritance
|
||||
|
||||
@@ -118,14 +131,14 @@ Special APIs
|
||||
.. _examples_instrumentation:
|
||||
|
||||
Attribute Instrumentation
|
||||
------------------------------------
|
||||
-------------------------
|
||||
|
||||
.. automodule:: examples.custom_attributes
|
||||
|
||||
.. _examples_sharding:
|
||||
|
||||
Horizontal Sharding
|
||||
------------------------
|
||||
-------------------
|
||||
|
||||
.. automodule:: examples.sharding
|
||||
|
||||
@@ -135,14 +148,14 @@ Extending the ORM
|
||||
.. _examples_caching:
|
||||
|
||||
Dogpile Caching
|
||||
------------------------
|
||||
---------------
|
||||
|
||||
.. automodule:: examples.dogpile_caching
|
||||
|
||||
.. _examples_postgis:
|
||||
|
||||
PostGIS Integration
|
||||
------------------------
|
||||
-------------------
|
||||
|
||||
.. automodule:: examples.postgis
|
||||
|
||||
|
||||
Vendored
+2
@@ -1,3 +1,5 @@
|
||||
.. _orm_exceptions_toplevel:
|
||||
|
||||
ORM Exceptions
|
||||
==============
|
||||
|
||||
|
||||
Vendored
+5
-5
@@ -3,10 +3,10 @@ Events and Internals
|
||||
====================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:maxdepth: 2
|
||||
|
||||
events
|
||||
internals
|
||||
exceptions
|
||||
deprecated
|
||||
events
|
||||
internals
|
||||
exceptions
|
||||
deprecated
|
||||
|
||||
|
||||
+69
-9
@@ -114,7 +114,7 @@ or dictionary is taken into account, so that the proxy should act just like
|
||||
the underlying collection or attribute does.
|
||||
|
||||
Creation of New Values
|
||||
-----------------------
|
||||
----------------------
|
||||
|
||||
When a list append() event (or set add(), dictionary __setitem__(), or scalar
|
||||
assignment event) is intercepted by the association proxy, it instantiates a
|
||||
@@ -151,7 +151,7 @@ Simplifying Association Objects
|
||||
|
||||
The "association object" pattern is an extended form of a many-to-many
|
||||
relationship, and is described at :ref:`association_pattern`. Association
|
||||
proxies are useful for keeping "association objects" out the way during
|
||||
proxies are useful for keeping "association objects" out of the way during
|
||||
regular use.
|
||||
|
||||
Suppose our ``userkeywords`` table above had additional columns
|
||||
@@ -256,7 +256,7 @@ by all these operations::
|
||||
.. _proxying_dictionaries:
|
||||
|
||||
Proxying to Dictionary Based Collections
|
||||
-----------------------------------------
|
||||
----------------------------------------
|
||||
|
||||
The association proxy can proxy to dictionary based collections as well. SQLAlchemy
|
||||
mappings usually use the :func:`.attribute_mapped_collection` collection type to
|
||||
@@ -484,9 +484,6 @@ using the :attr:`~.AssociationProxy.attr` attribute in a star-args context::
|
||||
|
||||
q = session.query(User).join(*User.keywords.attr)
|
||||
|
||||
.. versionadded:: 0.7.3
|
||||
:attr:`~.AssociationProxy.attr` attribute in a star-args context.
|
||||
|
||||
:attr:`~.AssociationProxy.attr` is composed of :attr:`.AssociationProxy.local_attr` and :attr:`.AssociationProxy.remote_attr`,
|
||||
which are just synonyms for the actual proxied attributes, and can also
|
||||
be used for querying::
|
||||
@@ -497,9 +494,58 @@ be used for querying::
|
||||
join(uka, User.keywords.local_attr).\
|
||||
join(ka, User.keywords.remote_attr)
|
||||
|
||||
.. versionadded:: 0.7.3
|
||||
:attr:`.AssociationProxy.local_attr` and :attr:`.AssociationProxy.remote_attr`,
|
||||
synonyms for the actual proxied attributes, and usable for querying.
|
||||
.. _cascade_scalar_deletes:
|
||||
|
||||
Cascading Scalar Deletes
|
||||
------------------------
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
Given a mapping as::
|
||||
|
||||
class A(Base):
|
||||
__tablename__ = 'test_a'
|
||||
id = Column(Integer, primary_key=True)
|
||||
ab = relationship(
|
||||
'AB', backref='a', uselist=False)
|
||||
b = association_proxy(
|
||||
'ab', 'b', creator=lambda b: AB(b=b),
|
||||
cascade_scalar_deletes=True)
|
||||
|
||||
|
||||
class B(Base):
|
||||
__tablename__ = 'test_b'
|
||||
id = Column(Integer, primary_key=True)
|
||||
ab = relationship('AB', backref='b', cascade='all, delete-orphan')
|
||||
|
||||
|
||||
class AB(Base):
|
||||
__tablename__ = 'test_ab'
|
||||
a_id = Column(Integer, ForeignKey(A.id), primary_key=True)
|
||||
b_id = Column(Integer, ForeignKey(B.id), primary_key=True)
|
||||
|
||||
An assigment to ``A.b`` will generate an ``AB`` object::
|
||||
|
||||
a.b = B()
|
||||
|
||||
The ``A.b`` association is scalar, and includes use of the flag
|
||||
:paramref:`.AssociationProxy.cascade_scalar_deletes`. When set, setting ``A.b``
|
||||
to ``None`` will remove ``A.ab`` as well::
|
||||
|
||||
a.b = None
|
||||
assert a.ab is None
|
||||
|
||||
When :paramref:`.AssociationProxy.cascade_scalar_deletes` is not set,
|
||||
the association object ``a.ab`` above would remain in place.
|
||||
|
||||
Note that this is not the behavior for collection-based association proxies;
|
||||
in that case, the intermediary association object is always removed when
|
||||
members of the proxied collection are removed. Whether or not the row is
|
||||
deleted depends on the relationship cascade setting.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`unitofwork_cascades`
|
||||
|
||||
API Documentation
|
||||
-----------------
|
||||
@@ -509,5 +555,19 @@ API Documentation
|
||||
.. autoclass:: AssociationProxy
|
||||
:members:
|
||||
:undoc-members:
|
||||
:inherited-members:
|
||||
|
||||
.. autoclass:: AssociationProxyInstance
|
||||
:members:
|
||||
:undoc-members:
|
||||
:inherited-members:
|
||||
|
||||
.. autoclass:: ObjectAssociationProxyInstance
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
.. autoclass:: ColumnAssociationProxyInstance
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
.. autodata:: ASSOCIATION_PROXY
|
||||
|
||||
Vendored
+111
-31
@@ -16,7 +16,7 @@ occur **once**, rather than for each time that query is built up and executed.
|
||||
The rationale for this system is to greatly reduce Python interpreter
|
||||
overhead for everything that occurs **before the SQL is emitted**.
|
||||
The caching of the "baked" system does **not** in any way reduce SQL calls or
|
||||
cache the **return results** from the database. A technique that demonstates
|
||||
cache the **return results** from the database. A technique that demonstrates
|
||||
the caching of the SQL calls and result sets themselves is available in
|
||||
:ref:`examples_caching`.
|
||||
|
||||
@@ -25,9 +25,12 @@ the caching of the SQL calls and result sets themselves is available in
|
||||
|
||||
.. note::
|
||||
|
||||
The :mod:`sqlalchemy.ext.baked` extension should be considered
|
||||
**experimental** as of 1.0.0. It provides a dramatically different system
|
||||
of producing queries which has yet to be proven at scale.
|
||||
The :mod:`sqlalchemy.ext.baked` extension is **not for beginners**. Using
|
||||
it correctly requires a good high level understanding of how SQLAlchemy, the
|
||||
database driver, and the backend database interact with each other. This
|
||||
extension presents a very specific kind of optimization that is not ordinarily
|
||||
needed. As noted above, it **does not cache queries**, only the string
|
||||
formulation of the SQL itself.
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
@@ -329,32 +332,113 @@ to arrive at the current "baked" approach. Starting from the
|
||||
management, removal of all redundant Python execution, and queries built up
|
||||
with conditionals needed to be addressed, leading to the final approach.
|
||||
|
||||
Special Query Techniques
|
||||
------------------------
|
||||
|
||||
This section will describe some techniques for specific query situations.
|
||||
|
||||
.. _baked_in:
|
||||
|
||||
Using IN expressions
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The :meth:`.ColumnOperators.in_` method in SQLAlchemy historically renders
|
||||
a variable set of bound parameters based on the list of items that's passed
|
||||
to the method. This doesn't work for baked queries as the length of that
|
||||
list can change on different calls. To solve this problem, the
|
||||
:paramref:`.bindparam.expanding` parameter supports a late-rendered IN
|
||||
expression that is safe to be cached inside of baked query. The actual list
|
||||
of elements is rendered at statement execution time, rather than at
|
||||
statement compilation time::
|
||||
|
||||
bakery = baked.bakery()
|
||||
|
||||
baked_query = bakery(lambda session: session.query(User))
|
||||
baked_query += lambda q: q.filter(
|
||||
User.name.in_(bindparam('username', expanding=True)))
|
||||
|
||||
result = baked_query.with_session(session).params(
|
||||
username=['ed', 'fred']).all()
|
||||
|
||||
.. seealso::
|
||||
|
||||
:paramref:`.bindparam.expanding`
|
||||
|
||||
:meth:`.ColumnOperators.in_`
|
||||
|
||||
Using Subqueries
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
When using :class:`.Query` objects, it is often needed that one :class:`.Query`
|
||||
object is used to generate a subquery within another. In the case where the
|
||||
:class:`.Query` is currently in baked form, an interim method may be used to
|
||||
retrieve the :class:`.Query` object, using the :meth:`.BakedQuery.to_query`
|
||||
method. This method is passed the :class:`.Session` or :class:`.Query` that is
|
||||
the argument to the lambda callable used to generate a particular step
|
||||
of the baked query::
|
||||
|
||||
bakery = baked.bakery()
|
||||
|
||||
# a baked query that will end up being used as a subquery
|
||||
my_subq = bakery(lambda s: s.query(User.id))
|
||||
my_subq += lambda q: q.filter(User.id == Address.user_id)
|
||||
|
||||
# select a correlated subquery in the top columns list,
|
||||
# we have the "session" argument, pass that
|
||||
my_q = bakery(
|
||||
lambda s: s.query(Address.id, my_subq.to_query(s).as_scalar()))
|
||||
|
||||
# use a correlated subquery in some of the criteria, we have
|
||||
# the "query" argument, pass that.
|
||||
my_q += lambda q: q.filter(my_subq.to_query(q).exists())
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
|
||||
Disabling Baked Queries Session-wide
|
||||
------------------------------------
|
||||
|
||||
The flag :paramref:`.Session.enable_baked_queries` may be set to False,
|
||||
causing all baked queries to not use the cache when used against that
|
||||
:class:`.Session`::
|
||||
|
||||
session = Session(engine, enable_baked_queries=False)
|
||||
|
||||
Like all session flags, it is also accepted by factory objects like
|
||||
:class:`.sessionmaker` and methods like :meth:`.sessionmaker.configure`.
|
||||
|
||||
The immediate rationale for this flag is to reduce memory use in the case
|
||||
that the query baking used by relationship loaders and other loaders
|
||||
is not desirable. It also can be used in the case that an application
|
||||
which is seeing issues potentially due to cache key conflicts from user-defined
|
||||
baked queries or other baked query issues can turn the behavior off, in
|
||||
order to identify or eliminate baked queries as the cause of an issue.
|
||||
|
||||
.. versionadded:: 1.2
|
||||
|
||||
Lazy Loading Integration
|
||||
------------------------
|
||||
|
||||
The baked query can be integrated with SQLAlchemy's lazy loader feature
|
||||
transparently. A future release of SQLAlchemy may enable this by default,
|
||||
as its use within lazy loading is completely transparent. For now,
|
||||
to enable baked lazyloading for all lazyloaders systemwide, call upon
|
||||
the :func:`.bake_lazy_loaders` function. This will impact all relationships
|
||||
that use the ``lazy='select'`` strategy as well as all use of the :func:`.lazyload`
|
||||
per-query strategy.
|
||||
The baked query system is integrated into SQLAlchemy's lazy loader feature
|
||||
as used by :func:`.relationship`, and will cache queries for most lazy
|
||||
load conditions. A small subset of
|
||||
"lazy loads" may not be cached; these involve query options in conjunction with ad-hoc
|
||||
:obj:`.aliased` structures that cannot produce a repeatable cache
|
||||
key.
|
||||
|
||||
"Baked" lazy loading may be enabled on a per-:func:`.relationship` basis
|
||||
using the ``baked_select`` loader strategy::
|
||||
.. versionchanged:: 1.2 "baked" queries are now the foundation of the
|
||||
lazy-loader feature of :func:`.relationship`.
|
||||
|
||||
class MyClass(Base):
|
||||
# ...
|
||||
|
||||
widgets = relationship("Widget", lazy="baked_select")
|
||||
|
||||
The ``baked_select`` strategy is available once any part of the application
|
||||
has imported the ``sqlalchemy.ext.baked`` module. The "bakery" used by
|
||||
this feature is local to the mapper for ``MyClass``.
|
||||
|
||||
For per-query use, the :func:`.baked_lazyload` strategy may be used,
|
||||
which works like any other loader option.
|
||||
Opting out with the bake_queries flag
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The :func:`.relationship` construct includes a flag
|
||||
:paramref:`.relationship.bake_queries` which when set to False will cause
|
||||
that relationship to opt out of caching queries. Additionally, the
|
||||
:paramref:`.Session.enable_baked_queries` setting can be used to disable
|
||||
all "baked query" use. These flags can be useful to conserve memory,
|
||||
when memory conservation is more important than performance for a particular
|
||||
relationship or for the application overall.
|
||||
|
||||
API Documentation
|
||||
-----------------
|
||||
@@ -364,13 +448,9 @@ API Documentation
|
||||
.. autoclass:: BakedQuery
|
||||
:members:
|
||||
|
||||
.. autoclass:: Bakery
|
||||
:members:
|
||||
|
||||
.. autoclass:: Result
|
||||
:members:
|
||||
|
||||
.. autofunction:: bake_lazy_loaders
|
||||
|
||||
.. autofunction:: unbake_lazy_loaders
|
||||
|
||||
.. autofunction:: baked_lazyload
|
||||
|
||||
.. autofunction:: baked_lazyload_all
|
||||
|
||||
+51
-4
@@ -49,8 +49,6 @@ assumed to be completed and the 'configure' step has finished::
|
||||
""
|
||||
# do something with mappings
|
||||
|
||||
.. versionadded:: 0.7.3
|
||||
|
||||
``__declare_first__()``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -68,7 +66,7 @@ configuration via the :meth:`.MapperEvents.before_configured` event::
|
||||
.. _declarative_abstract:
|
||||
|
||||
``__abstract__``
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
``__abstract__`` causes declarative to skip the production
|
||||
of a table or mapper for the class entirely. A class can be added within a
|
||||
@@ -109,6 +107,55 @@ created perhaps within distinct databases::
|
||||
DefaultBase.metadata.create_all(some_engine)
|
||||
OtherBase.metadata_create_all(some_other_engine)
|
||||
|
||||
.. versionadded:: 0.7.3
|
||||
|
||||
``__table_cls__``
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Allows the callable / class used to generate a :class:`.Table` to be customized.
|
||||
This is a very open-ended hook that can allow special customizations
|
||||
to a :class:`.Table` that one generates here::
|
||||
|
||||
class MyMixin(object):
|
||||
@classmethod
|
||||
def __table_cls__(cls, name, metadata, *arg, **kw):
|
||||
return Table(
|
||||
"my_" + name,
|
||||
metadata, *arg, **kw
|
||||
)
|
||||
|
||||
The above mixin would cause all :class:`.Table` objects generated to include
|
||||
the prefix ``"my_"``, followed by the name normally specified using the
|
||||
``__tablename__`` attribute.
|
||||
|
||||
``__table_cls__`` also supports the case of returning ``None``, which
|
||||
causes the class to be considered as single-table inheritance vs. its subclass.
|
||||
This may be useful in some customization schemes to determine that single-table
|
||||
inheritance should take place based on the arguments for the table itself,
|
||||
such as, define as single-inheritance if there is no primary key present::
|
||||
|
||||
class AutoTable(object):
|
||||
@declared_attr
|
||||
def __tablename__(cls):
|
||||
return cls.__name__
|
||||
|
||||
@classmethod
|
||||
def __table_cls__(cls, *arg, **kw):
|
||||
for obj in arg[1:]:
|
||||
if (isinstance(obj, Column) and obj.primary_key) or \
|
||||
isinstance(obj, PrimaryKeyConstraint):
|
||||
return Table(*arg, **kw)
|
||||
|
||||
return None
|
||||
|
||||
class Person(AutoTable, Base):
|
||||
id = Column(Integer, primary_key=True)
|
||||
|
||||
class Employee(Person):
|
||||
employee_name = Column(String)
|
||||
|
||||
The above ``Employee`` class would be mapped as single-table inheritance
|
||||
against ``Person``; the ``employee_name`` column would be added as a member
|
||||
of the ``Person`` table.
|
||||
|
||||
|
||||
.. versionadded:: 1.0.0
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user