-
Notifications
You must be signed in to change notification settings - Fork 4
/
sqlyoga_schema.livecodescript
3550 lines (2699 loc) · 115 KB
/
sqlyoga_schema.livecodescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
script "libSQLYogaSchema"
constant kErrErrorInFunction = 219
constant kErrCantFindObject = 619
command dbschema_load pSchemaFile
# code...
end dbschema_load
/**
Summary: Dispatches `RunMigration` to a stack file.
Parameters:
pMigrationVersion:
pStackFilename:
pConnectionA:
pDBKey:
Description:
*/
command dbschema_processMigrationFile pMigrationVersion, pStackFilename, pConnectionA, pDBKey
local tError
_beginProcessMigration pMigrationVersion, pConnectionA, pDBKey
if the result is not empty then return empty
try
dispatch "RunMigration" to stack pStackFilename with pConnectionA
dbschema_createTriggers pConnectionA
_endProcessMigration pMigrationVersion, pConnectionA
dbsynch_schemaWithDatabase pConnectionA, pDBKey
catch tError
finally
if there is a stack pStackFilename then
delete stack pStackFilename
end if
if tError is empty then
dbconn_commitTransaction empty, pConnectionA
else
dbconn_rollbackTransaction empty, pConnectionA
throw tError
end if
end try
return empty
end dbschema_processMigrationFile
/**
Summary:
*/
command dbschema_processMigrationArray pMigrationVersion, pMigrationA, pConnectionA, pDBKey
local tError, tTableA, tIndexA, tFieldA, tFieldsA
_beginProcessMigration pMigrationVersion, pConnectionA, pDBKey
if the result is not empty then return empty
try
repeat for each element tTableA in pMigrationA["migration"]["create tables"]
# Get fields into format that API expects
if tTableA["field order"] is empty then
repeat for each element tFieldA in tTableA["fields"]
put tFieldA["name"] & "," after tTableA["field order"]
put tFieldA into tFieldsA[tFieldA["name"]]
end repeat
delete the last char of tTableA["field order"]
end if
put tFieldsA into tTableA["fields"]
dbschema_createTable tTableA["name"], tTableA, pConnectionA, pDBKey
end repeat
repeat for each element tTableA in pMigrationA["migration"]["create fields"]
dbschema_createFields tTableA["table"], tTableA["fields"], pConnectionA, pDBKey
end repeat
repeat for each element tIndexA in pMigrationA["migration"]["create indexes"]
dbschema_createIndex tIndexA["name"], tIndexA, pConnectionA, pDBKey
end repeat
dbschema_createTriggers pConnectionA
_endProcessMigration pMigrationVersion, pConnectionA
dbsynch_schemaWithDatabase pConnectionA, pDBKey
local tRecA, tField
repeat for each element tTableA in pMigrationA["migration"]["create records"]
repeat for each element tRecordA in tTableA["records"]
put sqlrecord_createObject(tTableA["table"], pConnectionA, pDBKey) into tRecA
repeat for each key tField in tRecordA
sqlrecord_set tRecA, tField, tRecordA[tField]
end repeat
sqlrecord_create tRecA
end repeat
end repeat
catch tError
finally
if tError is empty then
dbconn_commitTransaction empty, pConnectionA
else
dbconn_rollbackTransaction empty, pConnectionA
throw tError
end if
end try
return empty
end dbschema_processMigrationArray
private command _beginProcessMigration pMigrationVersion, @rConnectionA, pDBKey
local tError
put dbobject_createConnectionArray(rConnectionA, pDBKey) into rConnectionA
dbconn_connect rConnectionA
_createSchemaMigrationsTable rConnectionA
_checkSchemaMigrationShouldRun pMigrationVersion, rConnectionA
put the result into tError
if tError is empty then
dbconn_beginTransaction empty, rConnectionA
end if
return tError for error
end _beginProcessMigration
private command _endProcessMigration pMigrationVersion, pConnectionA
_insertSchemaMigration pMigrationVersion, pConnectionA
return empty
end _endProcessMigration
private command _checkSchemaMigrationShouldRun pMigrationVersion, pConnectionA
local tError, tSQL, tVersion
put _getCurrentSchemaVersion(pConnectionA) into tVersion
if tVersion >= pMigrationVersion then
put "migration has already been applied" into tError
end if
return tError for error
end _checkSchemaMigrationShouldRun
private command _insertSchemaMigration pMigrationVersion, pConnectionA
local tSQL, tBindingsA, tRecords
local theAffectedRows
put pMigrationVersion + 0 into tBindingsA[1]
put "UPDATE schema SET version = :1" into tSQL
dbconn_executeWBindings tSQL, tBindingsA, pConnectionA
put it into theAffectedRows
if theAffectedRows is 0 then
put "INSERT INTO schema (version) VALUES (:1)" into tSQL
dbconn_executeWBindings tSQL, tBindingsA, pConnectionA
end if
return empty
end _insertSchemaMigration
private function _listTables pConnectionA
local tConnID, tTables, tError
put dbconn_get("connection id", pConnectionA) into tConnID
if dbconn_get("type", pConnectionA) is "valentina" then
local tTableCount, tTableRef
put VDatabase_TableCount( tConnID ) into tTableCount
repeat with i = 1 to tTableCount
put VDatabase_Table( tConnID, i) into tTableRef
put VTable_Name( tTableRef) & cr after tTables
end repeat
delete the last char of tTables
put _valentinaErrorSchema(tConnID) into tError
if tError is not empty then
sqlyoga__throwError sqlyoga__errorTypeFromError(pConnectionA, tError), \
"retrieving database tables:" && tError
end if
else
if dbconn_get("type", pConnectionA) is "mysql" then
put revDataFromQuery(tab, cr, tConnID, "SHOW TABLES") into tTables
else
put revDatabaseTableNames(tConnID) into tTables
end if
if item 1 of tTables is "revdberr" then
sqlyoga__throwError sqlyoga__errorTypeFromError(pConnectionA, item 2 to -1 of tTables), \
"retrieving database tables:" && item 2 to -1 of tTables
end if
end if
return tTables for value
end _listTables
/**
Summary: Returns the current version number of the database.
Parameters:
pConnectionA: A connection array.
Description:
This function returns 0 if the `version` table does not exist.
Returns: Version or error in result.
*/
private function _getCurrentSchemaVersion pConnectionA
local tSQL, tBindingsA
local tVersion = "0"
if "schema" is among the lines of _listTables(pConnectionA) then
put "SELECT version FROM schema" into tSQL
put dbconn_retrieveQueryAsData(tSQL, tBindingsA, empty, empty, pConnectionA) into tVersion
end if
return tVersion for value
end _getCurrentSchemaVersion
private command _createSchemaMigrationsTable pConnectionA
local tDBTables, tSQL
put revDatabaseTableNames(dbconn_get("connection id", pConnectionA)) into tDBTables
if "schema" is not among the lines of tDBTables then
put "CREATE TABLE schema (version varchar(255) NOT NULL UNIQUE)" into tSQL
dbconn_executeSQL tSQL, pConnectionA
end if
return empty
end _createSchemaMigrationsTable
/**
Summary: Updates the physical database schema to the schema version specified.
Parameters:
pVersion: The version to upgrade the database schema to.
Description:
DEPRECATED
Returns: Empty
*/
command dbschema_migrateToVersion pVersion, pConnectionA, pDBKey
local theContainer, theVersions, theSQL
local theError
put dbobject_createConnectionArray(pConnectionA, pDBKey) into pConnectionA
put dbobject_get("schema migrations", pConnectionA["database"]) into theContainer
repeat with i = 1 to the number of controls of theContainer
put the short name of button i of theContainer & cr after theVersions
end repeat
delete the last char of theVersions
sort lines of theVersions numeric by word 2 to -1 of each
dbconn_beginTransaction empty, pConnectionA
local theConnId, theQuotesA
put dbconn_get("connection id", pConnectionA) into theConnID
put dbconn_get("quotes") into theQuotesA
set the wholeMatches to true
if "schema" is not among the lines of revDatabaseTableNames(theConnID) then
put "CREATE TABLE " & theQuotesA["left"] & "schema" & theQuotesA["right"] & " (version integer NOT NULL)" into theSQL
dbconn_executeSQL theSQL, pConnectionA
put format("INSERT INTO %sschema%s (version) VALUES(0)", theQuotesA["left"], theQuotesA["right"]) into theSQL
dbconn_executeSQL theSQL, pConnectionA
end if
local theBindingsA, theInstalledVersion
put format("SELECT version FROM %sschema%s", theQuotesA["left"], theQuotesA["right"]) into theSQL
put empty into theBindingsA
put dbconn_retrieveQueryAsData(theSQL, theBindingsA, tab, cr, pConnectionA) into theInstalledVersion
local theControlName, theVersion, theLastInstalledVersion
repeat for each line theControlName in theVersions
put word 2 of theControlName into theVersion
if theVersion > pVersion then exit repeat
if theVersion > theInstalledVersion then
try
dispatch "InstallSchemaVersion" to button ("Version" && theVersion) of theContainer with pConnectionA
catch theError
end try
end if
if theError is empty then
put theVersion into theLastInstalledVersion
end if
if theError is not empty then exit repeat
end repeat
if theError is empty then
## Don't update if last installed version < installed version. May be running old version
## of software and trying to upgrade to latest vesion caused error because
## table/fields already existed.
if theLastInstalledVersion > theInstalledVersion then
put format("UPDATE %sschema%s SET version = " & theLastInstalledVersion, theQuotesA["left"], theQuotesA["right"]) into theSQL
dbconn_executeSQL theSQL, pConnectionA
end if
end if
if theError is empty then
dbconn_commitTransaction empty, pConnectionA
else
dbconn_rollbackTransaction empty, pConnectionA
end if
try
local theType, theDo
## Let db clean up
put dbconn_get("type", pConnectionA) into theType
replace space with empty in theType
put "_" & theType & "_afterMigration pConnectionA" into theDo
do theDo
catch e
sqlyoga__throwError kErrErrorInFunction, "afterMigration has not been defined for database type '" & theType & "'"
end try
if theError is not empty then
throw theError
end if
return empty
end dbschema_migrateToVersion
## Creates a table in the database
command dbschema_createTable pName, pTableA, pConnectionA, pDBKey
local theType, theEncoding
-- pTableA["primary key"]
-- pTableA["fields"]
-- pTableA["foreign keys"]
-- pTableA["indexes"]
put dbobject_createConnectionArray(pConnectionA, pDBKey) into pConnectionA
put dbconn_get("type", pConnectionA) into theType
## Get effective encoding
put pTableA["encoding"] into theEncoding
if theEncoding is empty then put dbobject_get("encoding", pConnectionA["database"]) into theEncoding
put theEncoding into pTableA["encoding"]
## fill in encoding and check for primary key field
repeat for each key theKey in pTableA["fields"]
if pTableA["fields"][theKey]["encoding"] is empty then
put theEncoding into pTableA["fields"][theKey]["encoding"]
end if
if pTableA["primary key"] is empty and pTableA["fields"][theKey]["name"] is "id" then
put "id" into pTableA["primary key"]
end if
end repeat
local theDo
try
replace space with empty in theType
put "_" & theType & "_dbCreateTable pName, pTableA, pConnectionA" into theDo
do theDo
catch e
sqlyoga__throwError kErrErrorInFunction, param(0) && "has not been defined for database type '" & theType & "'"
end try
local theIndexA
repeat with i = 1 to the number of elements of pTableA["indexes"]
put pTableA["indexes"][i] into theIndexA
if theIndexA["table"] is empty then
put pName into theIndexA["table"]
end if
dbschema_createIndex theIndexA["name"], theIndexA, pConnectionA
end repeat
return empty
end dbschema_createTable
command dbschema_deleteTable pName
end dbschema_deleteTable
command dbschema_createFields pTable, pFieldsA, pConnection, pDBKey
local theConnectionA
local theType, theEncoding
-- name
-- type
-- length
-- accepts null
-- default value
put dbobject_createConnectionArray(pConnection, pDBKey) into theConnectionA
put dbconn_get("type", theConnectionA) into theType
## Get effective encoding
put dbobject_get("encoding", theConnectionA["database"]) into theEncoding
## fill in encoding for fields
repeat for each key theKey in pFieldsA
if pFieldsA[theKey]["encoding"] is empty then
put theEncoding into pFieldsA[theKey]["encoding"]
end if
end repeat
local theDo
try
replace space with empty in theType
put "_" & theType & "_dbCreateFields pTable, pFieldsA, theConnectionA" into theDo
do theDo
catch e
sqlyoga__throwError kErrErrorInFunction, param(0) && "has not been defined for database type '" & theType & "'"
end try
# sync schema with table changes
dbschema_tableSet pTable, empty, empty, theConnectionA["database"]
dbsynch_schemaImportTable theConnectionA, pTable
return empty
end dbschema_createFields
command dbschema_deleteFields pTable, pFields, pConnection, pDBKey
local theConnectionA, theType, theDo
put dbobject_createConnectionArray(pConnection, pDBKey) into theConnectionA
put dbconn_get("type", theConnectionA) into theType
try
replace space with empty in theType
put "_" & theType & "_dbDeleteFields pTable, pFields, theConnectionA" into theDo
do theDo
catch e
sqlyoga__throwError kErrErrorInFunction, param(0) && "has not been defined for database type '" & theType & "'"
end try
# Sync schema with table changes
dbschema_tableSet pTable, empty, empty, theConnectionA["database"]
dbsynch_schemaImportTable theConnectionA, pTable
return empty
end dbschema_deleteFields
command dbschema_createIndex pName, pIndexA, pConnection, pDBKey
local theConnectionA, theType, theDo
-- table
-- type (unique, simple, fulltext, spatial)
-- length
-- fields[1].."name", "length", "sort order", "collation"
-- indexing method (btree, hash, rtree)
put dbobject_createConnectionArray(pConnection, pDBKey) into theConnectionA
put dbconn_get("type", theConnectionA) into theType
try
replace space with empty in theType
put "_" & theType & "_dbCreateTableIndexes pName, pIndexA, theConnectionA" into theDo
do theDo
catch e
sqlyoga__throwError kErrErrorInFunction, param(0) && "has not been defined for database type '" & theType & "'"
end try
return empty
end dbschema_createIndex
command dbschema_deleteIndex pIndexName, pTableName, pConnection, pDBKey
local theConnectionA, theType, theDo
put dbobject_createConnectionArray(pConnection, pDBKey) into theConnectionA
put dbconn_get("type", theConnectionA) into theType
try
replace space with empty in theType
put "_" & theType & "_dbDeleteIndex pIndexName, pTableName, pConnectionA" into theDo
do theDo
catch e
sqlyoga__throwError kErrErrorInFunction, param(0) && "has not been defined for database type '" & theType & "'"
end try
return empty
end dbschema_deleteIndex
command dbschema_createTriggers pConnection, pDBKey
local theConnectionA, theType, theDo
put dbobject_createConnectionArray(pConnection, pDBKey) into theConnectionA
put dbconn_get("type", theConnectionA) into theType
try
replace space with empty in theType
put "_" & theType & "_dbCreateForeignKeyConstraints theConnectionA" into theDo
do theDo
catch e
sqlyoga__throwError kErrErrorInFunction, param(0) && "has not been defined for database type '" & theType & "'"
end try
return empty
end dbschema_createTriggers
--> sql databases
/**
Summary: Makes any changes necessary to database to put it in synch with the current schema.
Parameters:
pConnectionA:
pDBKey:
Description:
Returns: empty
*/
command dbsynch_databaseWithSchema pConnectionA, pDBKey
local theError, i, theDBKey
local theConnectionID
local theDatabaseTables
local theDBType
local theSQL
local theTable, theTables
local theVersion
local theRecords
put dbobject_createConnectionArray(pConnectionA, pDBKey) into pConnectionA
set the wholeMatches to true
dbconn_connect pConnectionA
put it into theConnectionID
put dbconn_get("type", pConnectionA) into theDBType
put dbconn_get("database", pConnectionA) into theDBKey
replace space with empty in theDBType
put revDatabaseTableNames(theConnectionID) into theDatabaseTables
if item 1 of theDatabaseTables is "revdberr" then
sqlyoga__throwError sqlyoga__errorTypeFromError(pConnectionA, item 2 to -1 of theDatabaseTables), \
"failed to retrieve database table names:" && item 2 to -1 of theDatabaseTables
end if
## CREATE OR ALTER TABLES THAT EXIST IN SCHEMA
put dbschema_get("tables", theDBKey) into theTables
dbconn_beginTransaction empty, pConnectionA
try
repeat for each line theTable in theTables
if theTable is among the lines of theDatabaseTables then
dbsynch_dbAlterTable theTable, pConnectionA
else
dbsynch_dbCreateTable theTable, pConnectionA
end if
end repeat
## ANY REMAINING FOREIGN KEY OPERATIONS (ACTUAL FOREIGN KEYS THROUGH ALTERTABLE, CREATE TRIGGERS, ETC.)
local theDo
try
put "_" & theDBType & "_dbCreateForeignKeyConstraints pConnectionA" into theDo
do theDo
catch e
sqlyoga__throwError kErrErrorInFunction, param(0) && "has not been defined for database type '" & theDBType & "'"
end try
## Update schema table
_createSchemaMigrationsTable pConnectionA
put dbschema_get("version", theDBKey) into theVersion
_insertSchemaMigration theVersion, pConnectionA
catch theError
end try
if theError is empty then
dbconn_commitTransaction empty, pConnectionA
else
dbconn_rollbackTransaction empty, pConnectionA
end if
return empty
end dbsynch_databaseWithSchema
# Puts active schema in synch with database
command dbsynch_schemaWithDatabase pConnectionA, pDBKey
local theConnectionID
local theSchemaTables
local theTable, theTableA
local theTables
put dbobject_createConnectionArray(pConnectionA, pDBKey) into pConnectionA
set the wholeMatches to true
put dbconn_get("connection id", pConnectionA) into theConnectionID
if theConnectionID < 1 then
sqlyoga__throwError sqlyoga__errorTypeFromError(pConnectionA, "no connection"), "you must connect to the database before importing the schema"
end if
put _listTables(pConnectionA) into theTables
dbschema_reset pConnectionA["database"]
## Import tables
repeat for each line theTable in theTables
dbsynch_schemaImportTable pConnectionA, theTable
end repeat
# Set version
dbschema_set "version", _getCurrentSchemaVersion(pConnectionA), pConnectionA["database"]
return empty
end dbsynch_schemaWithDatabase
on dbsynch_dbDropTable pConnectionA, pTable
local theSQL
put format("DROP TABLE IF EXISTS '%s'", pTable) into theSQL
dbconn_executeSQL theSQL, pConnectionA
return empty
end dbsynch_dbDropTable
command dbsynch_dbCreateTable pTableName, pConnectionA
local theDBType
local theSQL
local theTableA
## NO FIELDS, NO CREATE
if dbschema_tableGet(pTableName, "fields", pConnectionA["database"]) is empty then return empty
-- put dbconn_get("type", pConnectionA) into theDBType
-- replace space with empty in theDBType
## CREATE TABLE
put dbsynch_createTableSQL(pTableName, pConnectionA) into theSQL
dbconn_executeSQL theSQL, pConnectionA
-- ## INDEXES
-- local theDo
-- put "_" & theDBType & "_dbCreateTableIndexes pConnectionA, pTableA" into theDo
-- do theDo
return empty
end dbsynch_dbCreateTable
function dbsynch_createTableSQL pTableName, pConnectionA
local theDBType, theDo
local theTableA, theSQL, theHandler
if dbschema_tableGet(pTableName, "fields", pConnectionA["database"]) is empty then
sqlyoga__throwError kErrErrorInFunction, param(0) && pTableName && "does not have any fields"
end if
put dbschema_tableGet(pTableName,, pConnectionA["database"]) into theTableA
try
put dbconn_get("type", pConnectionA) into theDBType
replace space with empty in theDBType
put "_" & theDBType & "_dbCreateTableSQL" into theHandler
put "put" && theHandler && "(pTableName, theTableA, pConnectionA) into theSQL" into theDo
do theDo
catch e
sqlyoga__throwError kErrErrorInFunction, param(0) && "has not been defined for database type '" & theDBType & "'"
end try
return theSQL
end dbsynch_createTableSQL
command dbsynch_dbAlterTable pTableName, pConnectionA
local theDBType, theDo, theHandler
local theTableA
if dbschema_tableGet(pTableName, "fields", pConnectionA["database"]) is empty then
sqlyoga__throwError kErrErrorInFunction, param(0) && pTableName && "does not have any fields"
end if
put dbschema_tableGet(pTableName,, pConnectionA["database"]) into theTableA
try
put dbconn_get("type", pConnectionA) into theDBType
replace space with empty in theDBType
put "_" & theDBType & "_dbAlterTable" into theHandler
put theHandler && "pTableName, theTableA, pConnectionA" into theDo
do theDo
catch e
sqlyoga__throwError kErrErrorInFunction, param(0) && "has not been defined for database type '" & theDBType & "'"
end try
return empty
end dbsynch_dbAlterTable
command dbsynch_schemaImportTable pConnectionA, pTable
local i
local theDBType, theSystemTables, theDo
local theField, theFieldA, theFields, theFieldsA, theIndexFields
local theIndex, theIndexA, theIndexName
local theIndexesA
local theOldFieldsA, theOldIndexesA
local theRelationshipsA
local theTableA
put dbconn_get("type", pConnectionA) into theDBType
replace space with empty in theDBType
## FILTER OUT DB CREATED TABLES
set the wholeMatches to true
try
put "put _" & theDBType & "_systemTables() into theSystemTables" into theDo
do theDo
put the result into theSystemTables
catch e
sqlyoga__throwError kErrErrorInFunction, "systemTables() has not been defined for database type '" & theDBType & "'"
end try
if pTable is among the lines of theSystemTables then
return empty
end if
--> theArrayA["fields"]
--> theArrayA["fields"][index]["length"] (string, text, binary, integer)
--> theArrayA["fields"][index]["precision"] (decimal)
--> theArrayA["fields"][index]["scale"] (decimal)
--> theArrayA["fields"][index]["signed"]
--> theArrayA["fields"][index]["primary key"]
--> theArrayA["fields"][index]["fixed width"] (for string, specifies varchar or char)
--> theArrayA["fields"][index]["default value"]
--> theArrayA["fields"][index]["unique"]
--> theArrayA["fields"][index]["accepts null"]
try
put "_" & theDBType & "_dbTableFields pConnectionA, pTable" into theDo
do theDo
put it into theTableA
catch e
sqlyoga__throwError kErrErrorInFunction, "dbTableFields has not been defined for database type '" & theDBType & "'"
end try
try
put "_" & theDBType & "_dbTableIndexes pConnectionA, pTable, theFieldsA " into theDo
do theDo
put it into theIndexesA
catch e
sqlyoga__throwError kErrErrorInFunction, "dbTableIndexes has not been defined for database type '" & theDBType & "'"
end try
set the wholeMatches to true
## Assign meta type to fields
repeat for each key theField in theTableA["fields"]
put _NormalizeFieldType(theTableA["fields"][theField]["type"]) into theTableA["fields"][theField]["meta type"]
end REPEAT
## Update list of primary key fields if need be. Multiple primary keys
## are stored as an index.
repeat for each key theIndexName in theIndexesA["indexes"]
if theIndexesA["indexes"][theIndexName]["primary key"] then
put theIndexesA["indexes"][theIndexName]["fields"] into theFields
split theFields by column
replace cr with comma in theFields[1]
put theFields[1] into theTableA["primary key"]
exit repeat
end if
end repeat
dbschema_addTableDefinition pTable, theTableA, pConnectionA["database"]
return empty
end dbsynch_schemaImportTable
-- splits a field type into type and length
-- values come out in parameters
command dbsynch_splitFieldType pFieldType, @rType, @rLength, @rSigned
local theOffset
put empty into rType
put empty into rLength
put empty into rSigned
put offset("(", pFieldType) into theOffset
if theOffset > 0 then
put char 1 to theOffset - 1 of pFieldType into rType
put char theOffset + 1 to offset(")", pFieldType) - 1 of pFieldType into rLength
else
put word 1 of pFieldType into rType
end if
put word 2 of pFieldType is "signed" into rSigned
return empty
end dbsynch_splitFieldType
command dbsynch_dbTableCreateSQL pConnectionA, pTable
local theColumn
local theConnectionID
local theCreateTableSQL
local theCursor
local theQs,theSQL
local theType
put dbconn_get("connection id", pConnectionA) into theConnectionID
put dbconn_get("type", pConnectionA) into theType
put dbconn_get("quotes", pConnectionA) into theQs
put theQs["left"] & pTable & theQs["right"] into pTable
switch theType
case "mysql"
put "show create table" && pTable into theSQL
put "Create Table" into theColumn
break
case "sqlite"
put "SELECT sql FROM sqlite_master WHERE name =" && pTable & " AND type = 'table'" into theSQL
put "sql" into theColumn
break
case "valentina"
break
case "postgresql"
break
case "sql server"
break
end SWITCH
put revQueryDatabase(theConnectionID, theSQL) into theCursor
if theCursor is an integer then
put revDatabaseColumnNamed(theCursor, theColumn) into theCreateTableSQL
revCloseCursor theCursor
else
sqlyoga__throwError sqlyoga__errorTypeFromError(pConnectionA, theCursor), "unable to retrieve create table SQL from database"
end if
return theCreateTableSQL for value
end dbsynch_dbTableCreateSQL
--> Driver: SQLite
private command _sqlite_dbTableFields pConnectionA, pTable
local leftQ,rightQ,theA
local theConnectionID
local theCursor
local theField
local thePrimaryKeys
local theQuotesA
local theSQL
put dbconn_get("connection id", pConnectionA) into theConnectionID
put dbconn_get("quotes", pConnectionA) into theQuotesA
put theQuotesA["left"] into leftQ
put theQuotesA["right"] into rightQ
put "PRAGMA table_info(" & leftQ & pTable & rightQ & ")" into theSQL
put revQueryDatabase(theConnectionID, theSQL) into theCursor
if theCursor is not an integer then
sqlyoga__throwError sqlyoga__errorTypeFromError(pConnectionA, theCursor), "retrieving table fields"
end if
if revQueryIsAtEnd(theCursor) then
revCloseCursor theCursor
sqlyoga__throwError sqlyoga__errorTypeFromError(pConnectionA, "no fields"), \
"no fields were returned for table '" & pTable & "'"
end if
-- Returns cid, name, type, notnull, dflt_value, pk
repeat forever
put revDatabaseColumnNamed(theCursor, "name") into theField
put theField & comma after theA["field order"]
put theField into theA["fields"][theField]["name"]
put empty into theA["fields"][theField]["encoding"]
put revDatabaseColumnNamed(theCursor, "dflt_value") into theA["fields"][theField]["default value"]
## An empty string would have a ''. Default to NULL
if theA["fields"][theField]["default value"] is empty then put "NULL" into theA["fields"][theField]["default value"]
put revDatabaseColumnNamed(theCursor, "notnull") is "0" into theA["fields"][theField]["accepts null"] # value is 99 for null
put revDatabaseColumnNamed(theCursor, "pk") > 0 into theA["fields"][theField]["primary key"] # value is 0 for not primary
put false into theA["fields"][theField]["unique"]
if theA["fields"][theField]["primary key"] then
put theField & comma after thePrimaryKeys
end if
## Note: default value is wrapped in '' if a string. Or it could be something like CURRENT_DATE if it is a sqlite function.
local theType, theLength, isSigned
dbsynch_splitFieldType revDatabaseColumnNamed(theCursor, "Type"), theType, theLength, isSigned
put theType into theA["fields"][theField]["type"]
put theLength into theA["fields"][theField]["length"]
put isSigned into theA["fields"][theField]["signed"]
revMoveToNextRecord theCursor
if the result is not true then exit REPEAT
end repeat
delete the last char of thePrimaryKeys
put thePrimaryKeys into theA["primary key"]
delete the last char of theA["field order"]
## INTEGER PRIMARY KEY IS AN AUTOINCREMENT IN SQLITE
## ALTHOUGH IT WILL REUSE NUMBERS
## AUTOINCREMENT KEYWORD MEANS THE TABLE WILL MAX OUT
if the number of items of thePrimaryKeys is 1 then
if theA["fields"][thePrimaryKeys]["type"] is "integer" then
put "sequence" into theA["fields"][thePrimaryKeys]["type"]
put empty into theA["fields"][thePrimaryKeys]["length"]
put false into theA["fields"][thePrimaryKeys]["signed"]
put true into theA["fields"][thePrimaryKeys]["unique"] # primary has to be unique
end if
end if
revCloseCursor theCursor
return theA for value
end _sqlite_dbTableFields
private command _sqlite_dbTableRelationships pConnectionA, pTable
local theConnectionID, theQuotesA, leftQ, rightQ
local theSQL, theCursor
put dbconn_get("connection id", pConnectionA) into theConnectionID
put dbconn_get("quotes", pConnectionA) into theQuotesA
put theQuotesA["left"] into leftQ
put theQuotesA["right"] into rightQ
-- create array of relationships the table has with other tables
put "PRAGMA foreign_key_list(" & leftQ & pTable & rightQ & ")" into theSQL
put revQueryDatabase(theConnectionID, theSQL) into theCursor
if theCursor is not an integer then
sqlyoga__throwError sqlyoga__errorTypeFromError(pConnectionA, theCursor), "retrieving foreign key list" && theCursor
end if
if not revQueryIsAtEnd(theCursor) then
local theIndex, theReferencedTable, theSourceColumns, theReferencedColumns, theA
repeat forever
add 1 to theIndex
put revDatabaseColumnNamed(theCursor, "table") into theReferencedTable
put revDatabaseColumnNamed(theCursor, "from") into theSourceColumns
put revDatabaseColumnNamed(theCursor, "to") into theReferencedColumns
put theSourceColumns into theA[theIndex]["from key"]
put theReferencedTable into theA[theIndex]["to table"]
put theReferencedColumns into theA[theIndex]["to key"]
revMoveToNextRecord theCursor
if the result is not true then exit repeat
end repeat
end if
revCloseCursor theCursor
return theA for value
end _sqlite_dbTableRelationships
private command _sqlite_dbTableIndexes pConnectionA, pTable, pFieldsA
local leftQ,rightQ
local theA,theSQL
local theConnectionID