@@ -248,6 +248,7 @@ typedef struct ms_MSSQL2008_layer_info_t {
248
248
char * index_name ; /* hopefully this isn't necessary - but if the optimizer ain't cuttin' it... */
249
249
char * sort_spec ; /* the sort by specification which should be applied to the generated select statement */
250
250
int mssqlversion_major ; /* the sql server major version number */
251
+ int paging ; /* Driver handling of pagination, enabled by default */
251
252
SQLSMALLINT * itemtypes ; /* storing the sql field types for further reference */
252
253
253
254
msODBCconn * conn ; /* Connection to db */
@@ -979,6 +980,7 @@ int msMSSQL2008LayerOpen(layerObj *layer)
979
980
layerinfo -> conn = NULL ;
980
981
layerinfo -> itemtypes = NULL ;
981
982
layerinfo -> mssqlversion_major = 0 ;
983
+ layerinfo -> paging = MS_TRUE ;
982
984
983
985
layerinfo -> conn = (msODBCconn * ) msConnPoolRequest (layer );
984
986
@@ -1339,6 +1341,8 @@ static int prepare_database(layerObj *layer, rectObj rect, char **query_string)
1339
1341
char * data_source = 0 ;
1340
1342
char * f_table_name = 0 ;
1341
1343
char * geom_table = 0 ;
1344
+ char * tmp = 0 ;
1345
+ char * paging_query = 0 ;
1342
1346
/*
1343
1347
"Geometry::STGeomFromText('POLYGON(())',)" + terminator = 40 chars
1344
1348
Plus 10 formatted doubles (15 digits of precision, a decimal point, a space/comma delimiter each = 17 chars each)
@@ -1446,32 +1450,66 @@ static int prepare_database(layerObj *layer, rectObj rect, char **query_string)
1446
1450
/* start creating the query */
1447
1451
1448
1452
query = msStringConcatenate (query , "SELECT " );
1453
+ if (layerinfo -> paging && (layer -> maxfeatures >= 0 || layer -> startindex > 0 ))
1454
+ paging_query = msStringConcatenate (paging_query , "SELECT " );
1449
1455
1450
1456
/* adding items to the select list */
1451
1457
for (t = 0 ; t < layer -> numitems ; t ++ ) {
1452
1458
#ifdef USE_ICONV
1453
- query = msStringConcatenate (query , "convert(nvarchar(max), [" );
1454
- query = msStringConcatenate (query , layer -> items [t ]);
1455
- query = msStringConcatenate (query , "])," );
1459
+ query = msStringConcatenate (query , "convert(nvarchar(max), [" );
1456
1460
#else
1457
1461
query = msStringConcatenate (query , "convert(varchar(max), [" );
1458
- query = msStringConcatenate (query , layer -> items [t ]);
1459
- query = msStringConcatenate (query , "])," );
1460
1462
#endif
1463
+ query = msStringConcatenate (query , layer -> items [t ]);
1464
+ query = msStringConcatenate (query , "]) '" );
1465
+ tmp = msIntToString (t );
1466
+ query = msStringConcatenate (query , tmp );
1467
+ if (paging_query ) {
1468
+ paging_query = msStringConcatenate (paging_query , "[" );
1469
+ paging_query = msStringConcatenate (paging_query , tmp );
1470
+ paging_query = msStringConcatenate (paging_query , "], " );
1471
+ }
1472
+ msFree (tmp );
1473
+ query = msStringConcatenate (query , "'," );
1461
1474
}
1462
1475
1463
1476
/* adding geometry column */
1464
1477
query = msStringConcatenate (query , "[" );
1465
1478
query = msStringConcatenate (query , layerinfo -> geom_column );
1466
1479
if (layerinfo -> geometry_format == MSSQLGEOMETRY_NATIVE )
1467
- query = msStringConcatenate (query , "]," );
1468
- else
1469
- query = msStringConcatenate (query , "].STAsBinary()," );
1480
+ query = msStringConcatenate (query , "] 'geom'," );
1481
+ else {
1482
+ query = msStringConcatenate (query , "].STAsBinary() 'geom'," );
1483
+ }
1470
1484
1471
1485
/* adding id column */
1472
1486
query = msStringConcatenate (query , "convert(varchar(36), [" );
1473
1487
query = msStringConcatenate (query , layerinfo -> urid_name );
1474
- query = msStringConcatenate (query , "]) FROM " );
1488
+ if (paging_query ) {
1489
+ paging_query = msStringConcatenate (paging_query , "[geom], [id] FROM (" );
1490
+ query = msStringConcatenate (query , "]) 'id', row_number() over (" );
1491
+ if (layerinfo -> sort_spec ) {
1492
+ query = msStringConcatenate (query , layerinfo -> sort_spec );
1493
+ }
1494
+
1495
+ if (layer -> sortBy .nProperties > 0 ) {
1496
+ tmp = msLayerBuildSQLOrderBy (layer );
1497
+ if (layerinfo -> sort_spec )
1498
+ query = msStringConcatenate (query , ", " );
1499
+ else
1500
+ query = msStringConcatenate (query , " ORDER BY " );
1501
+ query = msStringConcatenate (query , tmp );
1502
+ msFree (tmp );
1503
+ }
1504
+ else {
1505
+ query = msStringConcatenate (query , "ORDER BY " );
1506
+ query = msStringConcatenate (query , layerinfo -> urid_name );
1507
+ }
1508
+ query = msStringConcatenate (query , ") 'rownum' FROM " );
1509
+ }
1510
+ else {
1511
+ query = msStringConcatenate (query , "]) 'id' FROM " );
1512
+ }
1475
1513
1476
1514
/* adding the source */
1477
1515
query = msStringConcatenate (query , data_source );
@@ -1510,19 +1548,44 @@ static int prepare_database(layerObj *layer, rectObj rect, char **query_string)
1510
1548
query = msStringConcatenate (query , box3d );
1511
1549
query = msStringConcatenate (query , ") = 1 " );
1512
1550
1513
- if (layerinfo -> sort_spec ) {
1514
- query = msStringConcatenate (query , layerinfo -> sort_spec );
1515
- }
1551
+ if (paging_query ) {
1552
+ paging_query = msStringConcatenate (paging_query , query );
1553
+ paging_query = msStringConcatenate (paging_query , ") tbl where [rownum] " );
1554
+ if (layer -> startindex > 0 ) {
1555
+ tmp = msIntToString (layer -> startindex );
1556
+ paging_query = msStringConcatenate (paging_query , ">= " );
1557
+ paging_query = msStringConcatenate (paging_query , tmp );
1558
+ if (layer -> maxfeatures >= 0 ) {
1559
+ msFree (tmp );
1560
+ tmp = msIntToString (layer -> startindex + layer -> maxfeatures );
1561
+ paging_query = msStringConcatenate (paging_query , " and [rownum] < " );
1562
+ paging_query = msStringConcatenate (paging_query , tmp );
1563
+ }
1564
+ }
1565
+ else {
1566
+ tmp = msIntToString (layer -> maxfeatures );
1567
+ paging_query = msStringConcatenate (paging_query , "< " );
1568
+ paging_query = msStringConcatenate (paging_query , tmp );
1569
+ }
1570
+ msFree (tmp );
1571
+ msFree (query );
1572
+ query = paging_query ;
1573
+ }
1574
+ else {
1575
+ if (layerinfo -> sort_spec ) {
1576
+ query = msStringConcatenate (query , layerinfo -> sort_spec );
1577
+ }
1516
1578
1517
- /* Add extra sort by */
1518
- if ( layer -> sortBy .nProperties > 0 ) {
1519
- char * pszTmp = msLayerBuildSQLOrderBy (layer );
1520
- if (layerinfo -> sort_spec )
1521
- query = msStringConcatenate (query , ", " );
1522
- else
1523
- query = msStringConcatenate (query , " ORDER BY " );
1524
- query = msStringConcatenate (query , pszTmp );
1525
- msFree (pszTmp );
1579
+ /* Add extra sort by */
1580
+ if (layer -> sortBy .nProperties > 0 ) {
1581
+ char * pszTmp = msLayerBuildSQLOrderBy (layer );
1582
+ if (layerinfo -> sort_spec )
1583
+ query = msStringConcatenate (query , ", " );
1584
+ else
1585
+ query = msStringConcatenate (query , " ORDER BY " );
1586
+ query = msStringConcatenate (query , pszTmp );
1587
+ msFree (pszTmp );
1588
+ }
1526
1589
}
1527
1590
1528
1591
@@ -2453,6 +2516,140 @@ int msMSSQL2008LayerGetShape(layerObj *layer, shapeObj *shape, resultObj *record
2453
2516
return msMSSQL2008LayerGetShapeRandom (layer , shape , & (layerinfo -> row_num ));
2454
2517
}
2455
2518
2519
+ /*
2520
+ ** Returns the number of shapes that match the potential filter and extent.
2521
+ * rectProjection is the projection in which rect is expressed, or can be NULL if
2522
+ * rect should be considered in the layer projection.
2523
+ * This should be equivalent to calling msLayerWhichShapes() and counting the
2524
+ * number of shapes returned by msLayerNextShape(), honouring layer->maxfeatures
2525
+ * limitation if layer->maxfeatures>=0, and honouring layer->startindex if
2526
+ * layer->startindex >= 1 and paging is enabled.
2527
+ * Returns -1 in case of failure.
2528
+ */
2529
+ int msMSSQL2008LayerGetShapeCount (layerObj * layer , rectObj rect , projectionObj * rectProjection )
2530
+ {
2531
+ msMSSQL2008LayerInfo * layerinfo ;
2532
+ char * query = 0 ;
2533
+ char result_data [256 ];
2534
+ char box3d [40 + 10 * 22 + 11 ];
2535
+ SQLLEN retLen ;
2536
+ SQLRETURN rc ;
2537
+ int hasFilter = MS_FALSE ;
2538
+
2539
+ rectObj searchrectInLayerProj = rect ;
2540
+
2541
+ if (layer -> debug ) {
2542
+ msDebug ("msMSSQL2008LayerGetShapeCount called.\n" );
2543
+ }
2544
+
2545
+ layerinfo = getMSSQL2008LayerInfo (layer );
2546
+
2547
+ if (!layerinfo ) {
2548
+ /* Layer not open */
2549
+ msSetError (MS_QUERYERR , "msMSSQL2008LayerGetShapeCount called on unopened layer (layerinfo = NULL)" , "msMSSQL2008LayerGetShapeCount()" );
2550
+
2551
+ return MS_FAILURE ;
2552
+ }
2553
+
2554
+ // Special processing if the specified projection for the rect is different from the layer projection
2555
+ // We want to issue a WHERE that includes
2556
+ // ((the_geom && rect_reprojected_in_layer_SRID) AND NOT ST_Disjoint(ST_Transform(the_geom, rect_SRID), rect))
2557
+ if (rectProjection != NULL && layer -> project &&
2558
+ msProjectionsDiffer (& (layer -> projection ), rectProjection ))
2559
+ {
2560
+ // If we cannot guess the EPSG code of the rectProjection, fallback on slow implementation
2561
+ if (rectProjection -> numargs < 1 ||
2562
+ strncasecmp (rectProjection -> args [0 ], "init=epsg:" , strlen ("init=epsg:" )) != 0 )
2563
+ {
2564
+ if (layer -> debug ) {
2565
+ msDebug ("msMSSQL2008LayerGetShapeCount(): cannot find EPSG code of rectProjection. Falling back on client-side feature count.\n" );
2566
+ }
2567
+ return LayerDefaultGetShapeCount (layer , rect , rectProjection );
2568
+ }
2569
+
2570
+ // Reproject the passed rect into the layer projection and get
2571
+ // the SRID from the rectProjection
2572
+ msProjectRect (rectProjection , & (layer -> projection ), & searchrectInLayerProj ); /* project the searchrect to source coords */
2573
+ }
2574
+
2575
+ if (searchrectInLayerProj .minx == searchrectInLayerProj .maxx ||
2576
+ searchrectInLayerProj .miny == searchrectInLayerProj .maxy ) {
2577
+ /* create point shape for rectangles with zero area */
2578
+ snprintf (box3d , sizeof (box3d ), "%s::STGeomFromText('POINT(%.15g %.15g)',%s)" , /* %s.STSrid)", */
2579
+ layerinfo -> geom_column_type , searchrectInLayerProj .minx , searchrectInLayerProj .miny , layerinfo -> user_srid );
2580
+ }
2581
+ else {
2582
+ snprintf (box3d , sizeof (box3d ), "%s::STGeomFromText('POLYGON((%.15g %.15g,%.15g %.15g,%.15g %.15g,%.15g %.15g,%.15g %.15g))',%s)" , /* %s.STSrid)", */
2583
+ layerinfo -> geom_column_type ,
2584
+ searchrectInLayerProj .minx , searchrectInLayerProj .miny ,
2585
+ searchrectInLayerProj .maxx , searchrectInLayerProj .miny ,
2586
+ searchrectInLayerProj .maxx , searchrectInLayerProj .maxy ,
2587
+ searchrectInLayerProj .minx , searchrectInLayerProj .maxy ,
2588
+ searchrectInLayerProj .minx , searchrectInLayerProj .miny ,
2589
+ layerinfo -> user_srid
2590
+ );
2591
+ }
2592
+
2593
+ msLayerTranslateFilter (layer , & layer -> filter , layer -> filteritem );
2594
+
2595
+ /* set up statement */
2596
+ query = msStringConcatenate (query , "SELECT count(*) FROM " );
2597
+ query = msStringConcatenate (query , layerinfo -> geom_table );
2598
+
2599
+ /* adding attribute filter */
2600
+ if (layer -> filter .native_string ) {
2601
+ query = msStringConcatenate (query , " WHERE (" );
2602
+ query = msStringConcatenate (query , layer -> filter .native_string );
2603
+ query = msStringConcatenate (query , ")" );
2604
+ hasFilter = MS_TRUE ;
2605
+ }
2606
+ else if (msLayerGetProcessingKey (layer , "NATIVE_FILTER" ) != NULL ) {
2607
+ query = msStringConcatenate (query , " WHERE (" );
2608
+ query = msStringConcatenate (query , msLayerGetProcessingKey (layer , "NATIVE_FILTER" ));
2609
+ query = msStringConcatenate (query , ")" );
2610
+ hasFilter = MS_TRUE ;
2611
+ }
2612
+
2613
+ /* adding spatial filter */
2614
+ if (hasFilter == MS_FALSE )
2615
+ query = msStringConcatenate (query , " WHERE " );
2616
+ else
2617
+ query = msStringConcatenate (query , " AND " );
2618
+
2619
+ query = msStringConcatenate (query , layerinfo -> geom_column );
2620
+ query = msStringConcatenate (query , ".MakeValid().STIntersects(" );
2621
+ query = msStringConcatenate (query , box3d );
2622
+ query = msStringConcatenate (query , ") = 1 " );
2623
+
2624
+ if (!executeSQL (layerinfo -> conn , query )) {
2625
+ msFree (query );
2626
+ return -1 ;
2627
+ }
2628
+
2629
+ msFree (query );
2630
+
2631
+ rc = SQLFetch (layerinfo -> conn -> hstmt );
2632
+
2633
+ if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO ) {
2634
+ if (layer -> debug ) {
2635
+ msDebug ("msMSSQL2008LayerGetShapeCount: No results found.\n" );
2636
+ }
2637
+
2638
+ return -1 ;
2639
+ }
2640
+
2641
+ rc = SQLGetData (layerinfo -> conn -> hstmt , 1 , SQL_C_CHAR , result_data , sizeof (result_data ), & retLen );
2642
+
2643
+ if (rc == SQL_ERROR ) {
2644
+ msSetError (MS_QUERYERR , "Failed to get feature count" , "msMSSQL2008LayerGetShapeCount()" );
2645
+ return -1 ;
2646
+ }
2647
+
2648
+ result_data [retLen ] = 0 ;
2649
+
2650
+ return atoi (result_data );
2651
+ }
2652
+
2456
2653
/* Query the DB for info about the requested table */
2457
2654
int msMSSQL2008LayerGetItems (layerObj * layer )
2458
2655
{
@@ -2804,6 +3001,32 @@ char *msMSSQL2008LayerEscapeSQLParam(layerObj *layer, const char *pszString)
2804
3001
return pszEscapedStr ;
2805
3002
}
2806
3003
3004
+ int msMSSQL2008GetPaging (layerObj * layer )
3005
+ {
3006
+ msMSSQL2008LayerInfo * layerinfo = NULL ;
3007
+
3008
+ if (!msMSSQL2008LayerIsOpen (layer ))
3009
+ return MS_TRUE ;
3010
+
3011
+ assert (layer -> layerinfo != NULL );
3012
+ layerinfo = (msMSSQL2008LayerInfo * )layer -> layerinfo ;
3013
+
3014
+ return layerinfo -> paging ;
3015
+ }
3016
+
3017
+ void msMSSQL2008EnablePaging (layerObj * layer , int value )
3018
+ {
3019
+ msMSSQL2008LayerInfo * layerinfo = NULL ;
3020
+
3021
+ if (!msMSSQL2008LayerIsOpen (layer ))
3022
+ msMSSQL2008LayerOpen (layer );
3023
+
3024
+ assert (layer -> layerinfo != NULL );
3025
+ layerinfo = (msMSSQL2008LayerInfo * )layer -> layerinfo ;
3026
+
3027
+ layerinfo -> paging = value ;
3028
+ }
3029
+
2807
3030
int process_node (layerObj * layer , expressionObj * filter )
2808
3031
{
2809
3032
char * snippet = NULL ;
@@ -3413,6 +3636,12 @@ int msMSSQL2008LayerGetShape(layerObj *layer, shapeObj *shape, long record)
3413
3636
return MS_FAILURE ;
3414
3637
}
3415
3638
3639
+ int msMSSQL2008LayerGetShapeCount (layerObj * layer , rectObj rect , projectionObj * rectProjection )
3640
+ {
3641
+ msSetError (MS_QUERYERR , "msMSSQL2008LayerGetShapeCount called but unimplemented!(mapserver not compiled with MSSQL2008 support)" , "msMSSQL2008LayerGetShapeCount()" );
3642
+ return MS_FAILURE ;
3643
+ }
3644
+
3416
3645
int msMSSQL2008LayerGetExtent (layerObj * layer , rectObj * extent )
3417
3646
{
3418
3647
msSetError (MS_QUERYERR , "msMSSQL2008LayerGetExtent called but unimplemented!(mapserver not compiled with MSSQL2008 support)" , "msMSSQL2008LayerGetExtent()" );
@@ -3437,6 +3666,18 @@ int msMSSQL2008LayerGetItems(layerObj *layer)
3437
3666
return MS_FAILURE ;
3438
3667
}
3439
3668
3669
+ void msMSSQL2008EnablePaging (layerObj * layer , int value )
3670
+ {
3671
+ msSetError (MS_QUERYERR , "msMSSQL2008EnablePaging called but unimplemented!(mapserver not compiled with MSSQL2008 support)" , "msMSSQL2008EnablePaging()" );
3672
+ return ;
3673
+ }
3674
+
3675
+ int msMSSQL2008GetPaging (layerObj * layer )
3676
+ {
3677
+ msSetError (MS_QUERYERR , "msMSSQL2008GetPaging called but unimplemented!(mapserver not compiled with MSSQL2008 support)" , "msMSSQL2008GetPaging()" );
3678
+ return MS_FAILURE ;
3679
+ }
3680
+
3440
3681
int msMSSQL2008LayerTranslateFilter (layerObj * layer , expressionObj * filter , char * filteritem )
3441
3682
{
3442
3683
msSetError (MS_QUERYERR , "msMSSQL2008LayerTranslateFilter called but unimplemented!(mapserver not compiled with MSSQL2008 support)" , "msMSSQL2008LayerTranslateFilter()" );
@@ -3465,6 +3706,8 @@ MS_DLL_EXPORT int PluginInitializeVirtualTable(layerVTableObj* vtable, layerObj
3465
3706
assert (layer != NULL );
3466
3707
assert (vtable != NULL );
3467
3708
3709
+ vtable -> LayerEnablePaging = msMSSQL2008EnablePaging ;
3710
+ vtable -> LayerGetPaging = msMSSQL2008GetPaging ;
3468
3711
vtable -> LayerTranslateFilter = msMSSQL2008LayerTranslateFilter ;
3469
3712
vtable -> LayerEscapeSQLParam = msMSSQL2008LayerEscapeSQLParam ;
3470
3713
vtable -> LayerEscapePropertyName = msMSSQL2008LayerEscapePropertyName ;
@@ -3476,6 +3719,7 @@ MS_DLL_EXPORT int PluginInitializeVirtualTable(layerVTableObj* vtable, layerObj
3476
3719
vtable -> LayerWhichShapes = msMSSQL2008LayerWhichShapes ;
3477
3720
vtable -> LayerNextShape = msMSSQL2008LayerNextShape ;
3478
3721
vtable -> LayerGetShape = msMSSQL2008LayerGetShape ;
3722
+ vtable -> LayerGetShapeCount = msMSSQL2008LayerGetShapeCount ;
3479
3723
3480
3724
vtable -> LayerClose = msMSSQL2008LayerClose ;
3481
3725
@@ -3503,6 +3747,8 @@ msMSSQL2008LayerInitializeVirtualTable(layerObj *layer)
3503
3747
assert (layer != NULL );
3504
3748
assert (layer -> vtable != NULL );
3505
3749
3750
+ layer -> vtable -> LayerEnablePaging = msMSSQL2008EnablePaging ;
3751
+ layer -> vtable -> LayerGetPaging = msMSSQL2008GetPaging ;
3506
3752
layer -> vtable -> LayerTranslateFilter = msMSSQL2008LayerTranslateFilter ;
3507
3753
layer -> vtable -> LayerEscapeSQLParam = msMSSQL2008LayerEscapeSQLParam ;
3508
3754
layer -> vtable -> LayerEscapePropertyName = msMSSQL2008LayerEscapePropertyName ;
@@ -3514,7 +3760,7 @@ msMSSQL2008LayerInitializeVirtualTable(layerObj *layer)
3514
3760
layer -> vtable -> LayerWhichShapes = msMSSQL2008LayerWhichShapes ;
3515
3761
layer -> vtable -> LayerNextShape = msMSSQL2008LayerNextShape ;
3516
3762
layer -> vtable -> LayerGetShape = msMSSQL2008LayerGetShape ;
3517
- /* layer->vtable->LayerGetShapeCount, use default */
3763
+ layer -> vtable -> LayerGetShapeCount = msMSSQL2008LayerGetShapeCount ;
3518
3764
3519
3765
layer -> vtable -> LayerClose = msMSSQL2008LayerClose ;
3520
3766
0 commit comments